Commit 817bb38
Changed files (12)
pkg/mcp/content.go
@@ -0,0 +1,31 @@
+package mcp
+
+type Content interface {
+ GetType() string
+}
+
+type TextContent struct {
+ Type string `json:"type"`
+ Text string `json:"text"`
+}
+
+func (t TextContent) GetType() string {
+ return t.Type
+}
+
+type ImageContent struct {
+ Type string `json:"type"`
+ Data string `json:"data"`
+ MimeType string `json:"mimeType"`
+}
+
+func (i ImageContent) GetType() string {
+ return i.Type
+}
+
+func NewTextContent(text string) TextContent {
+ return TextContent{
+ Type: "text",
+ Text: text,
+ }
+}
\ No newline at end of file
pkg/mcp/initialize.go
@@ -0,0 +1,44 @@
+package mcp
+
+type InitializeRequest struct {
+ ProtocolVersion string `json:"protocolVersion"`
+ Capabilities Capabilities `json:"capabilities"`
+ ClientInfo ClientInfo `json:"clientInfo"`
+}
+
+type Capabilities struct {
+ Roots *RootsCapability `json:"roots,omitempty"`
+ Sampling *SamplingCapability `json:"sampling,omitempty"`
+ Experimental map[string]interface{} `json:"experimental,omitempty"`
+}
+
+type RootsCapability struct {
+ ListChanged bool `json:"listChanged,omitempty"`
+}
+
+type SamplingCapability struct{}
+
+type ClientInfo struct {
+ Name string `json:"name"`
+ Version string `json:"version"`
+}
+
+type InitializeResult struct {
+ ProtocolVersion string `json:"protocolVersion"`
+ Capabilities ServerCapabilities `json:"capabilities"`
+ ServerInfo ServerInfo `json:"serverInfo"`
+ Instructions string `json:"instructions,omitempty"`
+}
+
+type ServerCapabilities struct {
+ Logging *LoggingCapability `json:"logging,omitempty"`
+ Prompts *PromptsCapability `json:"prompts,omitempty"`
+ Resources *ResourcesCapability `json:"resources,omitempty"`
+ Roots *RootsCapability `json:"roots,omitempty"`
+ Tools *ToolsCapability `json:"tools,omitempty"`
+}
+
+type ServerInfo struct {
+ Name string `json:"name"`
+ Version string `json:"version"`
+}
\ No newline at end of file
pkg/mcp/jsonrpc.go
@@ -0,0 +1,25 @@
+package mcp
+
+import (
+ "encoding/json"
+)
+
+type JSONRPCRequest struct {
+ JSONRPC string `json:"jsonrpc"`
+ ID *int `json:"id,omitempty"`
+ Method string `json:"method"`
+ Params json.RawMessage `json:"params,omitempty"`
+}
+
+type JSONRPCResponse struct {
+ JSONRPC string `json:"jsonrpc"`
+ ID *int `json:"id,omitempty"`
+ Result *json.RawMessage `json:"result,omitempty"`
+ Error *JSONRPCError `json:"error,omitempty"`
+}
+
+type JSONRPCError struct {
+ Code int `json:"code"`
+ Message string `json:"message"`
+ Data interface{} `json:"data,omitempty"`
+}
\ No newline at end of file
pkg/mcp/logging.go
@@ -0,0 +1,32 @@
+package mcp
+
+type LoggingLevel string
+
+const (
+ LoggingLevelDebug LoggingLevel = "debug"
+ LoggingLevelInfo LoggingLevel = "info"
+ LoggingLevelNotice LoggingLevel = "notice"
+ LoggingLevelWarning LoggingLevel = "warning"
+ LoggingLevelError LoggingLevel = "error"
+ LoggingLevelCrit LoggingLevel = "crit"
+ LoggingLevelAlert LoggingLevel = "alert"
+ LoggingLevelEmerg LoggingLevel = "emerg"
+)
+
+type LoggingCapability struct{}
+
+type SetLoggingLevelRequest struct {
+ Level LoggingLevel `json:"level"`
+}
+
+type LoggingMessageNotification struct {
+ Level LoggingLevel `json:"level"`
+ Data interface{} `json:"data"`
+ Logger string `json:"logger,omitempty"`
+}
+
+type ProgressNotification struct {
+ ProgressToken string `json:"progressToken"`
+ Progress float64 `json:"progress"`
+ Total float64 `json:"total,omitempty"`
+}
\ No newline at end of file
pkg/mcp/mcp.go
@@ -0,0 +1,9 @@
+package mcp
+
+const (
+ ParseError = -32700
+ InvalidRequest = -32600
+ MethodNotFound = -32601
+ InvalidParams = -32602
+ InternalError = -32603
+)
\ No newline at end of file
pkg/mcp/prompt.go
@@ -0,0 +1,48 @@
+package mcp
+
+type PromptHandler func(GetPromptRequest) (GetPromptResult, error)
+
+type Prompt struct {
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Arguments []PromptArgument `json:"arguments,omitempty"`
+ Handler PromptHandler `json:"-"`
+}
+
+type PromptArgument struct {
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Required bool `json:"required,omitempty"`
+}
+
+type PromptsCapability struct {
+ ListChanged bool `json:"listChanged,omitempty"`
+}
+
+type ListPromptsResult struct {
+ Prompts []Prompt `json:"prompts"`
+}
+
+type GetPromptRequest struct {
+ Name string `json:"name"`
+ Arguments map[string]interface{} `json:"arguments,omitempty"`
+}
+
+type PromptMessage struct {
+ Role string `json:"role"`
+ Content Content `json:"content"`
+}
+
+type GetPromptResult struct {
+ Description string `json:"description,omitempty"`
+ Messages []PromptMessage `json:"messages"`
+}
+
+func NewPrompt(name, description string, arguments []PromptArgument, handler PromptHandler) Prompt {
+ return Prompt{
+ Name: name,
+ Description: description,
+ Arguments: arguments,
+ Handler: handler,
+ }
+}
\ No newline at end of file
pkg/mcp/resource.go
@@ -0,0 +1,37 @@
+package mcp
+
+type ResourceHandler func(ReadResourceRequest) (ReadResourceResult, error)
+
+type Resource struct {
+ URI string `json:"uri"`
+ Name string `json:"name"`
+ Description string `json:"description,omitempty"`
+ MimeType string `json:"mimeType,omitempty"`
+ Handler ResourceHandler `json:"-"`
+}
+
+type ResourcesCapability struct {
+ Subscribe bool `json:"subscribe,omitempty"`
+ ListChanged bool `json:"listChanged,omitempty"`
+}
+
+type ListResourcesResult struct {
+ Resources []Resource `json:"resources"`
+}
+
+type ReadResourceRequest struct {
+ URI string `json:"uri"`
+}
+
+type ReadResourceResult struct {
+ Contents []Content `json:"contents"`
+}
+
+func NewResource(uri, name, mimeType string, handler ResourceHandler) Resource {
+ return Resource{
+ URI: uri,
+ Name: name,
+ MimeType: mimeType,
+ Handler: handler,
+ }
+}
\ No newline at end of file
pkg/mcp/root.go
@@ -0,0 +1,17 @@
+package mcp
+
+type Root struct {
+ URI string `json:"uri"`
+ Name string `json:"name"`
+}
+
+type ListRootsResult struct {
+ Roots []Root `json:"roots"`
+}
+
+func NewRoot(uri, name string) Root {
+ return Root{
+ URI: uri,
+ Name: name,
+ }
+}
\ No newline at end of file
pkg/mcp/roots.go
@@ -1,20 +0,0 @@
-package mcp
-
-// ListRootsRequest represents a request to list available roots
-type ListRootsRequest struct {
- // No parameters for list_roots
-}
-
-// RootHandler defines the interface for handling root-related operations
-type RootHandler interface {
- // ListRoots returns all available roots for this server
- ListRoots() []Root
-}
-
-// NewRoot creates a new Root with the given URI and name
-func NewRoot(uri, name string) Root {
- return Root{
- URI: uri,
- Name: name,
- }
-}
pkg/mcp/server.go
@@ -1,340 +1,258 @@
package mcp
import (
- "bufio"
- "context"
- "encoding/json"
- "fmt"
- "log"
- "os"
- "strings"
+ "bufio"
+ "context"
+ "encoding/json"
+ "fmt"
+ "log"
+ "os"
+ "strings"
)
type Server struct {
- name string
- version string
- capabilities ServerCapabilities
+ name string
+ version string
+ capabilities ServerCapabilities
- tools map[string]Tool
- prompts map[string]Prompt
- resourceDefinitions map[string]Resource
- rootDefinitions map[string]Root
+ tools map[string]Tool
+ prompts map[string]Prompt
+ resourceDefinitions map[string]Resource
+ rootDefinitions map[string]Root
- initializeHandler func(InitializeRequest) (InitializeResult, error)
- shutdownHandler func() error
+ initializeHandler func(InitializeRequest) (InitializeResult, error)
+ shutdownHandler func() error
}
-type ResourceHandler func(ReadResourceRequest) (ReadResourceResult, error)
-func (s *Server) ListTools() []Tool {
- tools := make([]Tool, 0, len(s.tools))
- for _, tool := range s.tools {
- tools = append(tools, tool)
- }
- return tools
-}
-
-// ListPrompts returns all registered prompts
-func (s *Server) ListPrompts() []Prompt {
- prompts := make([]Prompt, 0, len(s.prompts))
- for _, prompt := range s.prompts {
- prompts = append(prompts, prompt)
- }
- return prompts
-}
-
-// ListResources returns all registered resources
-func (s *Server) ListResources() []Resource {
- resources := make([]Resource, 0, len(s.resourceDefinitions))
- for _, resource := range s.resourceDefinitions {
- resources = append(resources, resource)
- }
- return resources
-}
-
-// ListRoots returns all registered roots
-func (s *Server) ListRoots() []Root {
- roots := make([]Root, 0, len(s.rootDefinitions))
- for _, root := range s.rootDefinitions {
- roots = append(roots, root)
- }
- return roots
-}
-
-// Run starts the server and handles JSON-RPC over stdio
func (s *Server) Run(ctx context.Context) error {
- scanner := bufio.NewScanner(os.Stdin)
- encoder := json.NewEncoder(os.Stdout)
-
- for scanner.Scan() {
- line := scanner.Bytes()
-
- var req JSONRPCRequest
- if err := json.Unmarshal(line, &req); err != nil {
- s.sendError(encoder, nil, ParseError, "Parse error")
- continue
- }
-
- response := s.handleRequest(req)
- if err := encoder.Encode(response); err != nil {
- log.Printf("Error encoding response: %v", err)
- }
-
- // Check for shutdown
- if req.Method == "shutdown" {
- break
- }
- }
-
- if err := scanner.Err(); err != nil {
- return fmt.Errorf("scanner error: %w", err)
- }
-
- return nil
-}
-
-// handleRequest processes a JSON-RPC request
-func (s *Server) handleRequest(req JSONRPCRequest) JSONRPCResponse {
- switch req.Method {
- case "initialize":
- return s.handleInitialize(req)
- case "initialized":
- return s.handleInitialized(req)
- case "shutdown":
- return s.handleShutdown(req)
- case "tools/list":
- return s.handleListTools(req)
- case "tools/call":
- return s.handleCallTool(req)
- case "prompts/list":
- return s.handleListPrompts(req)
- case "prompts/get":
- return s.handleGetPrompt(req)
- case "resources/list":
- return s.handleListResources(req)
- case "resources/read":
- return s.handleReadResource(req)
- case "roots/list":
- return s.handleListRoots(req)
- default:
- return s.createErrorResponse(req.ID, MethodNotFound, "Method not found")
- }
-}
-
-func (s *Server) handleInitialize(req JSONRPCRequest) JSONRPCResponse {
- var initReq InitializeRequest
- if err := json.Unmarshal(req.Params, &initReq); err != nil {
- return s.createErrorResponse(req.ID, InvalidParams, "Invalid params")
- }
-
- result := InitializeResult{
- ProtocolVersion: "2025-06-18",
- Capabilities: s.capabilities,
- ServerInfo: ServerInfo{
- Name: s.name,
- Version: s.version,
- },
- }
-
- if s.initializeHandler != nil {
- if customResult, err := s.initializeHandler(initReq); err == nil {
- result = customResult
- }
- }
-
- return s.createSuccessResponse(req.ID, result)
-}
-
-func (s *Server) handleInitialized(req JSONRPCRequest) JSONRPCResponse {
- // Initialized notification - no response needed
- return JSONRPCResponse{
- JSONRPC: "2.0",
- ID: req.ID,
- }
-}
-
-func (s *Server) handleShutdown(req JSONRPCRequest) JSONRPCResponse {
- if s.shutdownHandler != nil {
- s.shutdownHandler()
- }
-
- return s.createSuccessResponse(req.ID, nil)
-}
-
-func (s *Server) handleListTools(req JSONRPCRequest) JSONRPCResponse {
- tools := s.ListTools()
- result := ListToolsResult{Tools: tools}
- return s.createSuccessResponse(req.ID, result)
-}
+ scanner := bufio.NewScanner(os.Stdin)
+ encoder := json.NewEncoder(os.Stdout)
-func (s *Server) handleCallTool(req JSONRPCRequest) JSONRPCResponse {
- var callReq CallToolRequest
- if err := json.Unmarshal(req.Params, &callReq); err != nil {
- return s.createErrorResponse(req.ID, InvalidParams, "Invalid params")
- }
+ for scanner.Scan() {
+ line := scanner.Bytes()
- tool, exists := s.tools[callReq.Name]
- if !exists {
- return s.createErrorResponse(req.ID, MethodNotFound, "Tool not found")
- }
+ var req JSONRPCRequest
+ if err := json.Unmarshal(line, &req); err != nil {
+ s.sendError(encoder, nil, ParseError, "Parse error")
+ continue
+ }
- result, err := tool.Handler(callReq)
- if err != nil {
- return s.createErrorResponse(req.ID, InternalError, err.Error())
- }
+ response := s.handleRequest(req)
+ if err := encoder.Encode(response); err != nil {
+ log.Printf("Error encoding response: %v", err)
+ }
- return s.createSuccessResponse(req.ID, result)
-}
-
-func (s *Server) handleListPrompts(req JSONRPCRequest) JSONRPCResponse {
- prompts := s.ListPrompts()
- result := ListPromptsResult{Prompts: prompts}
- return s.createSuccessResponse(req.ID, result)
-}
+ if req.Method == "shutdown" {
+ break
+ }
+ }
-func (s *Server) handleGetPrompt(req JSONRPCRequest) JSONRPCResponse {
- var promptReq GetPromptRequest
- if err := json.Unmarshal(req.Params, &promptReq); err != nil {
- return s.createErrorResponse(req.ID, InvalidParams, "Invalid params")
- }
+ if err := scanner.Err(); err != nil {
+ return fmt.Errorf("scanner error: %w", err)
+ }
- prompt, exists := s.prompts[promptReq.Name]
- if !exists {
- return s.createErrorResponse(req.ID, MethodNotFound, "Prompt not found")
- }
-
- result, err := prompt.Handler(promptReq)
- if err != nil {
- return s.createErrorResponse(req.ID, InternalError, err.Error())
- }
-
- return s.createSuccessResponse(req.ID, result)
+ return nil
}
-func (s *Server) handleListResources(req JSONRPCRequest) JSONRPCResponse {
- resources := s.ListResources()
- result := ListResourcesResult{Resources: resources}
- return s.createSuccessResponse(req.ID, result)
-}
-
-func (s *Server) handleListRoots(req JSONRPCRequest) JSONRPCResponse {
- roots := s.ListRoots()
- result := ListRootsResult{Roots: roots}
- return s.createSuccessResponse(req.ID, result)
+func (s *Server) handleRequest(req JSONRPCRequest) JSONRPCResponse {
+ handleInitialize := func() JSONRPCResponse {
+ var initReq InitializeRequest
+ if err := json.Unmarshal(req.Params, &initReq); err != nil {
+ return s.createErrorResponse(req.ID, InvalidParams, "Invalid params")
+ }
+
+ result := InitializeResult{
+ ProtocolVersion: "2025-06-18",
+ Capabilities: s.capabilities,
+ ServerInfo: ServerInfo{
+ Name: s.name,
+ Version: s.version,
+ },
+ }
+
+ if s.initializeHandler != nil {
+ if customResult, err := s.initializeHandler(initReq); err == nil {
+ result = customResult
+ }
+ }
+
+ return s.createSuccessResponse(req.ID, result)
+ }
+
+ handleInitialized := func() JSONRPCResponse {
+ return JSONRPCResponse{
+ JSONRPC: "2.0",
+ ID: req.ID,
+ }
+ }
+
+ handleShutdown := func() JSONRPCResponse {
+ if s.shutdownHandler != nil {
+ s.shutdownHandler()
+ }
+ return s.createSuccessResponse(req.ID, nil)
+ }
+
+ handleListTools := func() JSONRPCResponse {
+ tools := make([]Tool, 0, len(s.tools))
+ for _, tool := range s.tools {
+ tools = append(tools, tool)
+ }
+ result := ListToolsResult{Tools: tools}
+ return s.createSuccessResponse(req.ID, result)
+ }
+
+ handleCallTool := func() JSONRPCResponse {
+ var callReq CallToolRequest
+ if err := json.Unmarshal(req.Params, &callReq); err != nil {
+ return s.createErrorResponse(req.ID, InvalidParams, "Invalid params")
+ }
+
+ tool, exists := s.tools[callReq.Name]
+ if !exists {
+ return s.createErrorResponse(req.ID, MethodNotFound, "Tool not found")
+ }
+
+ result, err := tool.Handler(callReq)
+ if err != nil {
+ return s.createErrorResponse(req.ID, InternalError, err.Error())
+ }
+
+ return s.createSuccessResponse(req.ID, result)
+ }
+
+ handleListPrompts := func() JSONRPCResponse {
+ prompts := make([]Prompt, 0, len(s.prompts))
+ for _, prompt := range s.prompts {
+ prompts = append(prompts, prompt)
+ }
+ result := ListPromptsResult{Prompts: prompts}
+ return s.createSuccessResponse(req.ID, result)
+ }
+
+ handleGetPrompt := func() JSONRPCResponse {
+ var promptReq GetPromptRequest
+ if err := json.Unmarshal(req.Params, &promptReq); err != nil {
+ return s.createErrorResponse(req.ID, InvalidParams, "Invalid params")
+ }
+
+ prompt, exists := s.prompts[promptReq.Name]
+ if !exists {
+ return s.createErrorResponse(req.ID, MethodNotFound, "Prompt not found")
+ }
+
+ result, err := prompt.Handler(promptReq)
+ if err != nil {
+ return s.createErrorResponse(req.ID, InternalError, err.Error())
+ }
+
+ return s.createSuccessResponse(req.ID, result)
+ }
+
+ handleListResources := func() JSONRPCResponse {
+ resources := make([]Resource, 0, len(s.resourceDefinitions))
+ for _, resource := range s.resourceDefinitions {
+ resources = append(resources, resource)
+ }
+ result := ListResourcesResult{Resources: resources}
+ return s.createSuccessResponse(req.ID, result)
+ }
+
+ handleListRoots := func() JSONRPCResponse {
+ roots := make([]Root, 0, len(s.rootDefinitions))
+ for _, root := range s.rootDefinitions {
+ roots = append(roots, root)
+ }
+ result := ListRootsResult{Roots: roots}
+ return s.createSuccessResponse(req.ID, result)
+ }
+
+ handleReadResource := func() JSONRPCResponse {
+ var readReq ReadResourceRequest
+ if err := json.Unmarshal(req.Params, &readReq); err != nil {
+ return s.createErrorResponse(req.ID, InvalidParams, "Invalid params")
+ }
+
+ resource, exists := s.resourceDefinitions[readReq.URI]
+ if !exists {
+ for pattern, r := range s.resourceDefinitions {
+ if pattern != "" && readReq.URI != pattern &&
+ ((pattern == "file://" && strings.HasPrefix(readReq.URI, "file://")) ||
+ (strings.HasSuffix(pattern, "*") && strings.HasPrefix(readReq.URI, strings.TrimSuffix(pattern, "*")))) {
+ resource = r
+ exists = true
+ break
+ }
+ }
+ }
+
+ if !exists {
+ return s.createErrorResponse(req.ID, MethodNotFound, "Resource not found")
+ }
+
+ result, err := resource.Handler(readReq)
+ if err != nil {
+ return s.createErrorResponse(req.ID, InternalError, err.Error())
+ }
+
+ return s.createSuccessResponse(req.ID, result)
+ }
+
+ switch req.Method {
+ case "initialize":
+ return handleInitialize()
+ case "initialized":
+ return handleInitialized()
+ case "shutdown":
+ return handleShutdown()
+ case "tools/list":
+ return handleListTools()
+ case "tools/call":
+ return handleCallTool()
+ case "prompts/list":
+ return handleListPrompts()
+ case "prompts/get":
+ return handleGetPrompt()
+ case "resources/list":
+ return handleListResources()
+ case "resources/read":
+ return handleReadResource()
+ case "roots/list":
+ return handleListRoots()
+ default:
+ return s.createErrorResponse(req.ID, MethodNotFound, "Method not found")
+ }
}
-func (s *Server) handleReadResource(req JSONRPCRequest) JSONRPCResponse {
- var readReq ReadResourceRequest
- if err := json.Unmarshal(req.Params, &readReq); err != nil {
- return s.createErrorResponse(req.ID, InvalidParams, "Invalid params")
- }
-
- resource, exists := s.resourceDefinitions[readReq.URI]
- if !exists {
- // Try to find a pattern-based handler (e.g., for "file://" prefix)
- for pattern, r := range s.resourceDefinitions {
- if pattern != "" && readReq.URI != pattern &&
- ((pattern == "file://" && strings.HasPrefix(readReq.URI, "file://")) ||
- (strings.HasSuffix(pattern, "*") && strings.HasPrefix(readReq.URI, strings.TrimSuffix(pattern, "*")))) {
- resource = r
- exists = true
- break
- }
- }
- }
-
- if !exists {
- return s.createErrorResponse(req.ID, MethodNotFound, "Resource not found")
- }
-
- result, err := resource.Handler(readReq)
- if err != nil {
- return s.createErrorResponse(req.ID, InternalError, err.Error())
- }
-
- return s.createSuccessResponse(req.ID, result)
-}
func (s *Server) createSuccessResponse(id *int, result interface{}) JSONRPCResponse {
- var resultBytes *json.RawMessage
- if result != nil {
- bytes, _ := json.Marshal(result)
- rawMsg := json.RawMessage(bytes)
- resultBytes = &rawMsg
- }
-
- return JSONRPCResponse{
- JSONRPC: "2.0",
- ID: id,
- Result: resultBytes,
- }
+ var resultBytes *json.RawMessage
+ if result != nil {
+ bytes, _ := json.Marshal(result)
+ rawMsg := json.RawMessage(bytes)
+ resultBytes = &rawMsg
+ }
+
+ return JSONRPCResponse{
+ JSONRPC: "2.0",
+ ID: id,
+ Result: resultBytes,
+ }
}
func (s *Server) createErrorResponse(id *int, code int, message string) JSONRPCResponse {
- return JSONRPCResponse{
- JSONRPC: "2.0",
- ID: id,
- Error: &JSONRPCError{
- Code: code,
- Message: message,
- },
- }
+ return JSONRPCResponse{
+ JSONRPC: "2.0",
+ ID: id,
+ Error: &JSONRPCError{
+ Code: code,
+ Message: message,
+ },
+ }
}
func (s *Server) sendError(encoder *json.Encoder, id *int, code int, message string) {
- response := s.createErrorResponse(id, code, message)
- encoder.Encode(response)
-}
-
-// Helper function to create text content
-func NewTextContent(text string) TextContent {
- return TextContent{
- Type: "text",
- Text: text,
- }
-}
-
-// Helper function to create tool result
-func NewToolResult(content ...Content) CallToolResult {
- return CallToolResult{
- Content: content,
- }
-}
-
-// Helper function to create tool error result
-func NewToolError(message string) CallToolResult {
- return CallToolResult{
- Content: []Content{NewTextContent("Error: " + message)},
- IsError: true,
- }
-}
-
-// Helper function to create a new tool with all fields
-func NewTool(name, description string, inputSchema interface{}, handler ToolHandler) Tool {
- return Tool{
- Name: name,
- Description: description,
- InputSchema: inputSchema,
- Handler: handler,
- }
-}
-
-// Helper function to create a new resource with all fields
-func NewResource(uri, name, mimeType string, handler ResourceHandler) Resource {
- return Resource{
- URI: uri,
- Name: name,
- MimeType: mimeType,
- Handler: handler,
- }
-}
-
-// Helper function to create a new prompt with all fields
-func NewPrompt(name, description string, arguments []PromptArgument, handler PromptHandler) Prompt {
- return Prompt{
- Name: name,
- Description: description,
- Arguments: arguments,
- Handler: handler,
- }
+ response := s.createErrorResponse(id, code, message)
+ encoder.Encode(response)
}
pkg/mcp/tool.go
@@ -0,0 +1,50 @@
+package mcp
+
+type ToolHandler func(CallToolRequest) (CallToolResult, error)
+
+type Tool struct {
+ Name string `json:"name"`
+ Description string `json:"description"`
+ InputSchema interface{} `json:"inputSchema"`
+ Handler ToolHandler `json:"-"`
+}
+
+type ToolsCapability struct {
+ ListChanged bool `json:"listChanged,omitempty"`
+}
+
+type ListToolsResult struct {
+ Tools []Tool `json:"tools"`
+}
+
+type CallToolRequest struct {
+ Name string `json:"name"`
+ Arguments map[string]interface{} `json:"arguments,omitempty"`
+}
+
+type CallToolResult struct {
+ Content []Content `json:"content"`
+ IsError bool `json:"isError,omitempty"`
+}
+
+func NewTool(name, description string, inputSchema interface{}, handler ToolHandler) Tool {
+ return Tool{
+ Name: name,
+ Description: description,
+ InputSchema: inputSchema,
+ Handler: handler,
+ }
+}
+
+func NewToolResult(content ...Content) CallToolResult {
+ return CallToolResult{
+ Content: content,
+ }
+}
+
+func NewToolError(message string) CallToolResult {
+ return CallToolResult{
+ Content: []Content{NewTextContent("Error: " + message)},
+ IsError: true,
+ }
+}
\ No newline at end of file
pkg/mcp/types.go
@@ -1,237 +0,0 @@
-package mcp
-
-import (
- "encoding/json"
-)
-
-// JSON-RPC 2.0 types
-type JSONRPCRequest struct {
- JSONRPC string `json:"jsonrpc"`
- ID *int `json:"id,omitempty"`
- Method string `json:"method"`
- Params json.RawMessage `json:"params,omitempty"`
-}
-
-type JSONRPCResponse struct {
- JSONRPC string `json:"jsonrpc"`
- ID *int `json:"id,omitempty"`
- Result *json.RawMessage `json:"result,omitempty"`
- Error *JSONRPCError `json:"error,omitempty"`
-}
-
-type JSONRPCError struct {
- Code int `json:"code"`
- Message string `json:"message"`
- Data interface{} `json:"data,omitempty"`
-}
-
-// JSON-RPC error codes
-const (
- ParseError = -32700
- InvalidRequest = -32600
- MethodNotFound = -32601
- InvalidParams = -32602
- InternalError = -32603
-)
-
-// MCP Protocol types
-type InitializeRequest struct {
- ProtocolVersion string `json:"protocolVersion"`
- Capabilities Capabilities `json:"capabilities"`
- ClientInfo ClientInfo `json:"clientInfo"`
-}
-
-type Capabilities struct {
- Roots *RootsCapability `json:"roots,omitempty"`
- Sampling *SamplingCapability `json:"sampling,omitempty"`
- Experimental map[string]interface{} `json:"experimental,omitempty"`
-}
-
-type RootsCapability struct {
- ListChanged bool `json:"listChanged,omitempty"`
-}
-
-type SamplingCapability struct{}
-
-type ClientInfo struct {
- Name string `json:"name"`
- Version string `json:"version"`
-}
-
-type InitializeResult struct {
- ProtocolVersion string `json:"protocolVersion"`
- Capabilities ServerCapabilities `json:"capabilities"`
- ServerInfo ServerInfo `json:"serverInfo"`
- Instructions string `json:"instructions,omitempty"`
-}
-
-type ServerCapabilities struct {
- Logging *LoggingCapability `json:"logging,omitempty"`
- Prompts *PromptsCapability `json:"prompts,omitempty"`
- Resources *ResourcesCapability `json:"resources,omitempty"`
- Roots *RootsCapability `json:"roots,omitempty"`
- Tools *ToolsCapability `json:"tools,omitempty"`
-}
-
-type LoggingCapability struct{}
-type PromptsCapability struct {
- ListChanged bool `json:"listChanged,omitempty"`
-}
-type ResourcesCapability struct {
- Subscribe bool `json:"subscribe,omitempty"`
- ListChanged bool `json:"listChanged,omitempty"`
-}
-type ToolsCapability struct {
- ListChanged bool `json:"listChanged,omitempty"`
-}
-
-type ServerInfo struct {
- Name string `json:"name"`
- Version string `json:"version"`
-}
-
-// Tool types
-type ToolHandler func(CallToolRequest) (CallToolResult, error)
-
-type Tool struct {
- Name string `json:"name"`
- Description string `json:"description"`
- InputSchema interface{} `json:"inputSchema"`
- Handler ToolHandler `json:"-"`
-}
-
-type ListToolsResult struct {
- Tools []Tool `json:"tools"`
-}
-
-type CallToolRequest struct {
- Name string `json:"name"`
- Arguments map[string]interface{} `json:"arguments,omitempty"`
-}
-
-type CallToolResult struct {
- Content []Content `json:"content"`
- IsError bool `json:"isError,omitempty"`
-}
-
-// Content types
-type Content interface {
- GetType() string
-}
-
-type TextContent struct {
- Type string `json:"type"`
- Text string `json:"text"`
-}
-
-func (t TextContent) GetType() string {
- return t.Type
-}
-
-type ImageContent struct {
- Type string `json:"type"`
- Data string `json:"data"`
- MimeType string `json:"mimeType"`
-}
-
-func (i ImageContent) GetType() string {
- return i.Type
-}
-
-// Handler types
-type PromptHandler func(GetPromptRequest) (GetPromptResult, error)
-
-// Prompt types
-type Prompt struct {
- Name string `json:"name"`
- Description string `json:"description"`
- Arguments []PromptArgument `json:"arguments,omitempty"`
- Handler PromptHandler `json:"-"`
-}
-
-type PromptArgument struct {
- Name string `json:"name"`
- Description string `json:"description"`
- Required bool `json:"required,omitempty"`
-}
-
-type ListPromptsResult struct {
- Prompts []Prompt `json:"prompts"`
-}
-
-type GetPromptRequest struct {
- Name string `json:"name"`
- Arguments map[string]interface{} `json:"arguments,omitempty"`
-}
-
-type PromptMessage struct {
- Role string `json:"role"`
- Content Content `json:"content"`
-}
-
-type GetPromptResult struct {
- Description string `json:"description,omitempty"`
- Messages []PromptMessage `json:"messages"`
-}
-
-// Resource types
-type Resource struct {
- URI string `json:"uri"`
- Name string `json:"name"`
- Description string `json:"description,omitempty"`
- MimeType string `json:"mimeType,omitempty"`
- Handler ResourceHandler `json:"-"`
-}
-
-type ListResourcesResult struct {
- Resources []Resource `json:"resources"`
-}
-
-type ReadResourceRequest struct {
- URI string `json:"uri"`
-}
-
-type ReadResourceResult struct {
- Contents []Content `json:"contents"`
-}
-
-// Root types
-type Root struct {
- URI string `json:"uri"`
- Name string `json:"name"`
-}
-
-type ListRootsResult struct {
- Roots []Root `json:"roots"`
-}
-
-// Logging types
-type LoggingLevel string
-
-const (
- LoggingLevelDebug LoggingLevel = "debug"
- LoggingLevelInfo LoggingLevel = "info"
- LoggingLevelNotice LoggingLevel = "notice"
- LoggingLevelWarning LoggingLevel = "warning"
- LoggingLevelError LoggingLevel = "error"
- LoggingLevelCrit LoggingLevel = "crit"
- LoggingLevelAlert LoggingLevel = "alert"
- LoggingLevelEmerg LoggingLevel = "emerg"
-)
-
-type SetLoggingLevelRequest struct {
- Level LoggingLevel `json:"level"`
-}
-
-// Notification types
-type LoggingMessageNotification struct {
- Level LoggingLevel `json:"level"`
- Data interface{} `json:"data"`
- Logger string `json:"logger,omitempty"`
-}
-
-type ProgressNotification struct {
- ProgressToken string `json:"progressToken"`
- Progress float64 `json:"progress"`
- Total float64 `json:"total,omitempty"`
-}