MCP Tool Documentation
February 11, 2026 · View on GitHub
This document explains how to document your go-micro services so that AI agents can understand them better.
Overview
The MCP gateway automatically exposes your microservices as tools that AI agents (like Claude) can call. By adding proper documentation to your service handlers, you help agents understand:
- What the tool does - The purpose and behavior
- What parameters it needs - Types, formats, constraints
- What it returns - Response structure and meaning
- How to use it - Example inputs and outputs
Documentation Methods
go-micro automatically extracts documentation from your Go doc comments at registration time. You don't need to write any extra code!
1. Go Doc Comments (Automatic - Recommended)
Just write standard Go documentation comments on your handler methods:
// GetUser retrieves a user by ID from the database. Returns full profile including email, name, and preferences.
//
// @example {"id": "user-1"}
func (s *UserService) GetUser(ctx context.Context, req *GetUserRequest, rsp *GetUserResponse) error {
// implementation
}
When you register the handler, go-micro automatically:
- Extracts the doc comment as the tool description
- Parses the
@exampletag for example inputs - Registers everything in the service registry
- Makes it available to the MCP gateway
Supported Tags:
@example <json>- Example JSON input (highly recommended for AI agents)
That's it! No extra registration code needed:
// Documentation is extracted automatically from method comments
handler := service.Server().NewHandler(new(UserService))
service.Server().Handle(handler)
2. Manual Registration (Optional Override)
For more control or to override auto-extracted docs, use server.WithEndpointDocs():
handler := service.Server().NewHandler(
new(UserService),
server.WithEndpointDocs(map[string]server.EndpointDoc{
"UserService.GetUser": {
Description: "Custom description that overrides the comment",
Example: `{"id": "user-123"}`,
},
}),
)
Manual metadata takes precedence over auto-extracted comments.
3. Endpoint Scopes (Auth)
Use server.WithEndpointScopes() to declare the auth scopes required for each
endpoint. The MCP gateway reads these from the registry and enforces them when
an Auth provider is configured.
handler := service.Server().NewHandler(
new(BlogService),
server.WithEndpointScopes("Blog.Create", "blog:write"),
server.WithEndpointScopes("Blog.Delete", "blog:write", "blog:admin"),
server.WithEndpointScopes("Blog.Read", "blog:read"),
)
Scopes are stored as comma-separated values in endpoint metadata ("scopes" key)
and are propagated through the service registry just like descriptions and examples.
Gateway-Level Scope Overrides
An operator can also define or override scopes at the MCP gateway without modifying individual services. This is useful for centralized policy management:
mcp.Serve(mcp.Options{
Registry: reg,
Auth: authProvider,
Scopes: map[string][]string{
"blog.Blog.Create": {"blog:write"},
"blog.Blog.Delete": {"blog:admin"},
},
})
Gateway-level scopes take precedence over service-level scopes.
4. Struct Tags (For Field Descriptions)
Add descriptions to struct fields using the description tag:
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)"`
}
The description tag is used to generate parameter descriptions in the JSON Schema.
How It Works
Automatic Extraction Pipeline
1. Handler Registration (Your Service)
├─> You write Go doc comments on methods
├─> Call service.Server().NewHandler(yourHandler)
└─> go-micro automatically parses source files using go/ast
2. Documentation Extraction (Automatic)
├─> Read Go doc comments from handler method source
├─> Parse @example tags for sample inputs
├─> Extract struct tag descriptions
└─> Merge with any manual metadata (manual wins)
3. Service Registry
├─> Store endpoint metadata in registry.Endpoint.Metadata
├─> Metadata distributed with service information
└─> Available to all components (gateway, discovery, etc.)
4. MCP Gateway Discovery
├─> Query registry for services and endpoints
├─> Read description and example from endpoint.Metadata
└─> Generate JSON Schema with documentation
5. Tool Creation
└─> Create MCP tool with rich description for AI agents
Example Output
For a documented handler, the MCP gateway generates:
{
"name": "users.UserService.GetUser",
"description": "GetUser retrieves a user by ID from the database. Returns full profile including email, name, and preferences.",
"inputSchema": {
"type": "object",
"description": "This endpoint fetches a user's complete profile...",
"properties": {
"id": {
"type": "string",
"description": "User ID in UUID format (e.g., \"123e4567-e89b-12d3-a456-426614174000\")"
}
},
"required": ["id"],
"examples": [
"{\"id\": \"user-1\"}"
]
}
}
Best Practices
Write for AI, Not Just Humans
AI agents parse your documentation literally. Be explicit:
✅ Good:
// GetUser retrieves a user by their unique ID from the database.
// Returns the user's full profile including name, email, and preferences.
// If the user doesn't exist, returns an error with status 404.
//
// @param id {string} User ID in UUID v4 format (e.g., "123e4567-e89b-12d3-a456-426614174000")
// @return {User} User object with all profile fields populated
❌ Bad:
// Gets a user
func GetUser(...) // No details, no context
Specify Formats and Constraints
Tell agents exactly what format you expect:
✅ Good:
// @param email {string} Email address in RFC 5322 format (must contain @ and domain)
// @param age {number} User's age (integer between 0-150)
// @param phone {string} Phone number in E.164 format (e.g., "+14155552671")
❌ Bad:
// @param email {string} The email
// @param age {number} Age
Provide Real Examples
Show agents actual valid inputs:
✅ Good:
// @example
// {
// "name": "Alice Smith",
// "email": "alice@example.com",
// "age": 30,
// "phone": "+14155552671"
// }
❌ Bad:
// @example
// {
// "name": "string",
// "email": "string"
// }
Document Error Cases
Tell agents what can go wrong:
// GetUser retrieves a user by ID.
//
// Returns error if:
// - User ID is not a valid UUID
// - User does not exist (404)
// - Database is unavailable (503)
//
// @param id {string} User ID in UUID format
Use Descriptive Names
Field names should be self-explanatory:
✅ Good:
type CreateUserRequest struct {
FullName string `json:"full_name" description:"User's complete name"`
EmailAddress string `json:"email_address" description:"Primary email for contact"`
DateOfBirth string `json:"date_of_birth" description:"Birth date in YYYY-MM-DD format"`
}
❌ Bad:
type CreateUserRequest struct {
N string `json:"n"` // What is n?
E string `json:"e"` // What is e?
D string `json:"d"` // What is d?
}
Impact on Agent Performance
Without Documentation
Agent: "I need to call GetUser but I don't know what format the ID should be.
Is it a number? A string? A UUID? Let me try..."
❌ Calls with: {"id": 123}
❌ Calls with: {"id": "user123"}
❌ Calls with: {"id": "abc"}
✅ Calls with: {"id": "550e8400-e29b-41d4-a716-446655440000"} (after 4 attempts)
With Documentation
Agent: "GetUser needs an ID in UUID format. The example shows the format.
I'll use a valid UUID."
✅ Calls with: {"id": "550e8400-e29b-41d4-a716-446655440000"} (first attempt)
Result:
- 75% fewer failed calls
- Faster task completion
- Better user experience
Parser Implementation
The MCP gateway uses several parsers:
1. Go Doc Parser (parseServiceDocs)
- Extracts godoc comments from handler methods
- Parses JSDoc-style tags
- Returns
ToolDescriptionstruct
2. Struct Tag Parser (ParseStructTags)
- Reads
descriptiontags from struct fields - Generates JSON Schema with field descriptions
- Marks required vs optional fields (omitempty)
3. Comment Parser (ParseGoDocComment)
- Regex-based extraction of @param, @return, @example tags
- Splits summary from detailed description
- Builds structured documentation
4. Type Mapper (reflectTypeToJSONType)
- Converts Go types to JSON Schema types
- Handles: string, int, float, bool, array, object
- Used for automatic schema generation
Examples
See complete examples in:
examples/mcp/documented/- Fully documented serviceexamples/auth/- Auth service with documentationexamples/hello-world/- Basic service
Testing Documentation
1. List Tools
curl http://localhost:3000/mcp/tools | jq '.tools[0]'
Verify the description and schema are correct.
2. Use with Claude Code
Add to your Claude Code config and ask Claude to use your service. Claude will show you how it interprets your documentation.
3. Check Examples Work
Try the examples from your @example tags:
curl -X POST http://localhost:3000/mcp/call \
-H "Content-Type: application/json" \
-d '{
"tool": "users.UserService.GetUser",
"input": <your-example-json>
}'
Future Enhancements
Planned improvements:
- Auto-extract examples from test files
- Validate documentation completeness (lint)
- Generate documentation from OpenAPI specs
- Support custom validation rules in tags
- Interactive documentation editor
FAQ
Q: Do I need to document every field? A: Document fields that are ambiguous or have constraints. Self-explanatory fields can rely on the field name.
Q: Will this slow down my service? A: No. Documentation is parsed once at startup when the MCP gateway discovers services.
Q: Can I use OpenAPI/Swagger specs instead? A: Not yet, but it's planned. For now, use Go comments and struct tags.
Q: What if I don't document my handlers? A: The MCP gateway will still work, generating basic descriptions from method names and types. But agents will perform better with documentation.
Q: How do I know if my documentation is good? A: Test it with Claude Code. If Claude understands your service and calls it correctly on the first try, your documentation is good!
Q: How do I add auth scopes to my endpoints?
A: Use server.WithEndpointScopes() when registering your handler:
handler := service.Server().NewHandler(
new(MyService),
server.WithEndpointScopes("MyService.Create", "write"),
)
Or define scopes at the gateway level using Scopes in mcp.Options.
Q: Can I set scopes at the gateway without changing services?
A: Yes. Use the Scopes option on mcp.Options to define or override scopes for any tool at the gateway layer. This is useful for centralized policy management.
License
Apache 2.0