chore: import upstream snapshot with attribution
govulncheck / govulncheck (push) Has been cancelled
Lint / golangci-lint (push) Has been cancelled
Run Tests / Unit Tests (push) Has been cancelled
Run Tests / Etcd Integration Tests (push) Has been cancelled
Harness (E2E) / Harnesses (mock LLM) (push) Has been cancelled
Harness (E2E) / Provider harnesses (live LLM conformance) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:33 +08:00
commit e071084ebe
982 changed files with 160368 additions and 0 deletions
+306
View File
@@ -0,0 +1,306 @@
# Documented Service Example
This example demonstrates how to document your go-micro service handlers so that AI agents can understand them better. The MCP gateway parses Go comments and struct tags to generate rich tool descriptions.
## Documentation Features
### 1. **Go Doc Comments**
Standard Go documentation comments are used as the tool description:
```go
// GetUser retrieves a user by ID from the database.
//
// This endpoint fetches a user's complete profile including their name,
// email, and age. If the user doesn't exist, an error is returned.
func (u *Users) GetUser(ctx context.Context, req *GetUserRequest, rsp *GetUserResponse) error {
// ...
}
```
### 2. **JSDoc-Style Tags**
Use `@param`, `@return`, and `@example` tags for detailed documentation:
```go
// CreateUser creates a new user in the system.
//
// @param name {string} User's full name (required, 1-100 characters)
// @param email {string} User's email address (required, must be valid email format)
// @param age {number} User's age (optional, must be 0-150 if provided)
// @return {User} The newly created user with generated ID
// @example
// {
// "name": "Alice Smith",
// "email": "alice@example.com",
// "age": 30
// }
func (u *Users) CreateUser(ctx context.Context, req *CreateUserRequest, rsp *CreateUserResponse) error {
// ...
}
```
### 3. **Struct Tags**
Add `description` tags to struct fields for better schema:
```go
type User struct {
ID string `json:"id" description:"User's unique identifier (UUID format)"`
Name string `json:"name" description:"User's full name"`
Email string `json:"email" description:"User's email address"`
Age int `json:"age,omitempty" description:"User's age (optional)"`
}
```
## Running the Example
### 1. Start the Service
```bash
cd examples/mcp/documented
go run main.go
```
Output:
```
Users service starting...
Service: users
Endpoints:
- Users.GetUser
- Users.CreateUser
MCP Gateway: http://localhost:3000
```
### 2. Test MCP Tools
List available tools:
```bash
curl http://localhost:3000/mcp/tools | jq
```
You'll see rich descriptions:
```json
{
"tools": [
{
"name": "users.Users.GetUser",
"description": "GetUser retrieves a user by ID from the database",
"inputSchema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "User ID in UUID format (e.g., \"123e4567-e89b-12d3-a456-426614174000\")"
}
},
"required": ["id"],
"examples": [
"{\"id\": \"123e4567-e89b-12d3-a456-426614174000\"}"
]
}
},
{
"name": "users.Users.CreateUser",
"description": "CreateUser creates a new user in the system",
"inputSchema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "User's full name (required, 1-100 characters)"
},
"email": {
"type": "string",
"description": "User's email address (required, must be valid email format)"
},
"age": {
"type": "number",
"description": "User's age (optional, must be 0-150 if provided)"
}
},
"required": ["name", "email"],
"examples": [
"{\"name\": \"Alice Smith\", \"email\": \"alice@example.com\", \"age\": 30}"
]
}
}
]
}
```
### 3. Call a Tool
Get existing user:
```bash
curl -X POST http://localhost:3000/mcp/call \
-H "Content-Type: application/json" \
-d '{
"tool": "users.Users.GetUser",
"input": {"id": "user-1"}
}'
```
Create new user:
```bash
curl -X POST http://localhost:3000/mcp/call \
-H "Content-Type: application/json" \
-d '{
"tool": "users.Users.CreateUser",
"input": {
"name": "Alice Smith",
"email": "alice@example.com",
"age": 30
}
}'
```
### 4. Use with Claude Code
Add to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"users-service": {
"command": "go",
"args": ["run", "/path/to/examples/mcp/documented/main.go"]
}
}
}
```
Then in Claude Code, ask:
```
> You: "Show me user-1's profile"
Claude will:
1. See the GetUser tool with rich description
2. Understand it needs an "id" parameter (UUID format)
3. Call users.Users.GetUser with {"id": "user-1"}
4. Return the user profile
```
## Documentation Best Practices
### DO: Write Clear Descriptions
```go
// ✅ Good: Clear, explains what and why
// GetUser retrieves a user by ID from the database.
// Returns full profile including email, name, and preferences.
```
```go
// ❌ Bad: Vague, no context
// Get gets a user
```
### DO: Specify Parameter Constraints
```go
// ✅ Good: Specifies format and constraints
// @param id {string} User ID in UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000")
// @param age {number} User's age (must be 0-150)
```
```go
// ❌ Bad: No constraints or format
// @param id {string} The ID
```
### DO: Provide Examples
```go
// ✅ Good: Real example agents can use
// @example
// {
// "name": "Alice Smith",
// "email": "alice@example.com",
// "age": 30
// }
```
```go
// ❌ Bad: No example
// (agents have to guess the format)
```
### DO: Use Descriptive Struct Tags
```go
// ✅ Good: Explains what the field is
type User struct {
ID string `json:"id" description:"User's unique identifier (UUID format)"`
}
```
```go
// ❌ Bad: No description
type User struct {
ID string `json:"id"`
}
```
## How It Works
1. **Go Doc Parsing**
- The MCP gateway reads your service's Go comments
- First line becomes the tool description
- Full comment becomes the detailed description
2. **JSDoc Tag Parsing**
- `@param` tags enhance parameter descriptions
- `@return` tags describe what the tool returns
- `@example` tags provide usage examples
3. **Struct Tag Reading**
- `description` tags add context to fields
- `json:"field,omitempty"` marks optional fields
- Used to generate JSON Schema for parameters
4. **Schema Generation**
- Combines parsed documentation with type information
- Creates rich JSON Schema for each tool
- Agents use this to understand how to call your service
## Impact on Agent Performance
### Without Documentation
```
Tool: users.Users.GetUser
Description: Call GetUser on users service
Parameters: { "id": "string" }
```
Agent thinks: *"What's an ID? What format? What if I pass the wrong thing?"*
### With Documentation
```
Tool: users.Users.GetUser
Description: Retrieves a user by ID from the database. Returns full profile
including email, name, and preferences.
Parameters:
- id (string, required): User ID in UUID format
Example: "123e4567-e89b-12d3-a456-426614174000"
Example:
{"id": "user-1"}
```
Agent thinks: *"I need a UUID format ID. I can use 'user-1' from the example!"*
**Result:** Agent calls your service correctly on the first try!
## Next Steps
- Document all your service handlers with clear descriptions
- Add `@param`, `@return`, and `@example` tags
- Use `description` tags in struct fields
- Test with Claude Code to see how agents understand your services
## License
Apache 2.0
+137
View File
@@ -0,0 +1,137 @@
// Package main demonstrates how to document your service handlers for better
// AI agent integration using endpoint metadata.
//
// Services register descriptions with their endpoints, and the MCP gateway
// reads these descriptions from the registry to generate rich tool descriptions.
package main
import (
"context"
"fmt"
"log"
"go-micro.dev/v6"
"go-micro.dev/v6/gateway/mcp"
"go-micro.dev/v6/server"
)
// User represents a user in the system
type User struct {
ID string `json:"id" description:"User's unique identifier (UUID format)"`
Name string `json:"name" description:"User's full name"`
Email string `json:"email" description:"User's email address"`
Age int `json:"age,omitempty" description:"User's age (optional)"`
}
// GetUserRequest is the request for getting a user
type GetUserRequest struct {
ID string `json:"id" description:"User ID to retrieve"`
}
// GetUserResponse is the response containing user data
type GetUserResponse struct {
User *User `json:"user" description:"The requested user object"`
}
// CreateUserRequest is the request for creating a user
type CreateUserRequest struct {
Name string `json:"name" description:"User's full name (required)"`
Email string `json:"email" description:"User's email address (required)"`
Age int `json:"age,omitempty" description:"User's age (optional)"`
}
// CreateUserResponse contains the newly created user
type CreateUserResponse struct {
User *User `json:"user" description:"The newly created user"`
}
// Users service handles user-related operations
type Users struct {
users map[string]*User
}
// GetUser retrieves a user by ID from the database. Returns full profile including email, name, and preferences. If the user doesn't exist, an error is returned.
//
// @example {"id": "user-1"}
func (u *Users) GetUser(ctx context.Context, req *GetUserRequest, rsp *GetUserResponse) error {
user, exists := u.users[req.ID]
if !exists {
return fmt.Errorf("user not found: %s", req.ID)
}
rsp.User = user
return nil
}
// CreateUser creates a new user in the system. Validates the user data and creates a new profile. Name and email are required fields, while age is optional. Email must be unique across all users.
//
// @example {"name": "Alice Smith", "email": "alice@example.com", "age": 30}
func (u *Users) CreateUser(ctx context.Context, req *CreateUserRequest, rsp *CreateUserResponse) error {
// Validate input
if req.Name == "" || req.Email == "" {
return fmt.Errorf("name and email are required")
}
// Generate ID (simplified for example)
id := fmt.Sprintf("user-%d", len(u.users)+1)
user := &User{
ID: id,
Name: req.Name,
Email: req.Email,
Age: req.Age,
}
u.users[id] = user
rsp.User = user
return nil
}
func main() {
// Create service
service := micro.NewService("users",
micro.Address(":9090"),
// Start MCP gateway alongside the service
mcp.WithMCP(":3000"),
)
service.Init()
// Register handler with pre-populated test data.
// Documentation is automatically extracted from method comments.
// Use WithEndpointScopes to declare required auth scopes per endpoint.
if err := service.Handle(
&Users{
users: map[string]*User{
"user-1": {ID: "user-1", Name: "John Doe", Email: "john@example.com", Age: 25},
"user-2": {ID: "user-2", Name: "Jane Smith", Email: "jane@example.com", Age: 30},
},
},
server.WithEndpointScopes("Users.GetUser", "users:read"),
server.WithEndpointScopes("Users.CreateUser", "users:write"),
); err != nil {
log.Fatal(err)
}
log.Println("Users service starting...")
log.Println("Service: users")
log.Println("Endpoints:")
log.Println(" - Users.GetUser")
log.Println(" - Users.CreateUser")
log.Println("MCP Gateway: http://localhost:3000")
log.Println("")
log.Println("Test with:")
log.Println(" curl http://localhost:3000/mcp/tools")
log.Println("")
log.Println("Or add to Claude Code:")
log.Println(` "users-service": {`)
log.Println(` "command": "micro",`)
log.Println(` "args": ["mcp", "serve"]`)
log.Println(` }`)
// Run service
if err := service.Run(); err != nil {
log.Fatal(err)
}
}