What is an MCP Server
Understanding the MCP (Model Context Protocol) Server is key to solving the "M×N integration problem" between large language models (LLMs) and external systems (such as databases, APIs, tools, etc.). Simply put, it's like a "USB interface for AI," providing a standardized, secure, and extensible way for AI applications to access and utilize external information and capabilities.
Core Principles
The core principles of the MCP Server can be summarized as follows:
Standardized Protocol:
- MCP defines a universal communication protocol, usually based on JSON-RPC 2.0, for message exchange between AI applications (clients) and MCP servers.
- This protocol specifies message formats (request, response, notification, error), data types, and communication flows, ensuring seamless interoperability between AI applications and MCP servers from different vendors.
- It's similar to how HTTP enables web browsers to communicate, providing a common language for AI systems to understand and interact.
Client-Server Architecture:
- Host: Typically the AI application that users interact with directly, such as Claude Desktop or AI-powered IDEs (like Cursor, VS Code Copilot). The host contains the MCP client.
- Client: Maintains a 1:1 connection with the MCP server, forwarding host requests via the MCP protocol and returning server responses to the host.
- Server: A lightweight program focused on exposing specific capabilities. It can be a local process or a remote service. Each server provides a set of "tools," "resources," and "prompts."
- Tools: Functions or operations that the AI model can invoke, such as querying a database, sending messages, or performing web scraping. These are key for AI to perform specific tasks.
- Resources: Data sources accessible to the AI model, similar to GET endpoints in REST APIs, providing data but usually not performing complex computations.
- Prompts: Predefined instructions or templates to guide the AI model in using tools or resources optimally.
Dynamic Tool Discovery and Execution:
- MCP allows AI models to dynamically discover and utilize available tools at runtime, rather than being hardcoded. The AI can query the MCP server for the current list of available tools and decide how to use them based on context.
- When an AI application needs a function, it connects to the appropriate MCP server, which exposes its supported tools, resources, and prompts. The AI model can then invoke these tools via the MCP protocol to complete tasks.
Context Management:
- MCP allows data to be divided into manageable parts, improving AI processing efficiency.
- The server only receives necessary context information, while the complete conversation history is usually retained on the host side, ensuring data isolation and security.
Security and Access Control:
- Security is a core design principle of MCP. The host (where the AI model resides) controls client connection permissions, allowing users and organizations to strictly manage what the AI assistant can access.
- MCP servers should follow the principle of least privilege, ensuring servers can only access the specific data and functions they are authorized for, limiting the impact of potential security vulnerabilities.
- For example, sensitive operations (like modifying system state or accessing credentials) usually require explicit user approval.
Two-Way Communication:
- MCP supports bidirectional communication. This means the AI model can not only receive information but also trigger operations in external systems, enabling more dynamic and interactive applications.
Composability and Extensibility:
- MCP servers are designed to be highly composable. Each server provides isolated, focused functionality.
- Multiple servers can be seamlessly combined, and the shared protocol ensures interoperability. This modular design supports future extensibility and allows tools and resources to be updated, tested, and extended independently.
- The MCP protocol is relatively complex; a complete implementation must handle JSON-RPC 2.0 requests/responses, error handling, notifications, session management, and tool/resource/prompt registration and invocation.
- This example is a highly simplified version for demonstration purposes: how to create a listener that accepts Cursor connections and returns a basic "Hello World" tool. It does not include full MCP protocol features like tool invocation or context management.
- Cursor's MCP integration is evolving. This document is based on current documentation and community practice and may change in the future.
Golang MCP Server Example (Simplified)
This example creates a simple HTTP server simulating an MCP server, exposing a virtual tool called myTool.sayHello
. When Cursor tries to connect, we return some predefined tool definitions.
mcp_server.go
file:
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
// MCP response structure (simplified)
type MCPResponse struct {
Jsonrpc string `json:"jsonrpc"`
ID *json.RawMessage `json:"id,omitempty"`
Result interface{} `json:"result,omitempty"`
Error *MCPError `json:"error,omitempty"`
}
// MCP error structure (simplified)
type MCPError struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
// MCP request structure (simplified)
type MCPRequest struct {
Jsonrpc string `json:"jsonrpc"`
ID *json.RawMessage `json:"id,omitempty"`
Method string `json:"method"`
Params json.RawMessage `json:"params,omitempty"`
}
// Tool definition structure (simplified)
type Tool struct {
Name string `json:"name"`
Description string `json:"description"`
// A complete MCP tool definition would include 'parameters', 'return', etc.
}
// Resource definition structure (simplified)
type Resource struct {
Name string `json:"name"`
Description string `json:"description"`
Type string `json:"type"`
// A complete MCP resource definition would include 'schema'
}
// Prompt definition structure (simplified)
type Prompt struct {
Name string `json:"name"`
Description string `json:"description"`
Content string `json:"content"`
// A complete MCP prompt definition would include 'context'
}
// Structure for responding to 'host.initialize'
type InitializeResult struct {
Tools []Tool `json:"tools"`
Resources []Resource `json:"resources"`
Prompts []Prompt `json:"prompts"`
}
func main() {
http.HandleFunc("/", mcpHandler)
port := ":8080"
fmt.Printf("MCP Server listening on http://localhost%s\n", port)
log.Fatal(http.ListenAndServe(port, nil))
}
func mcpHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)
return
}
var req MCPRequest
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&req); err != nil {
sendError(w, r, -32700, "Parse error", nil)
return
}
fmt.Printf("Received MCP request: Method=%s, ID=%s\n", req.Method, string(*req.ID))
var resp MCPResponse
resp.Jsonrpc = "2.0"
resp.ID = req.ID
switch req.Method {
case "host.initialize":
result := InitializeResult{
Tools: []Tool{{
Name: "myTool.sayHello",
Description: "Says hello to the given name.",
}},
Resources: []Resource{{
Name: "myResource.currentTime",
Description: "Returns the current time.",
Type: "text",
}},
Prompts: []Prompt{{
Name: "myPrompt.greeting",
Description: "A prompt for greetings.",
Content: "Hello, how can I assist you today?",
}},
}
resp.Result = result
case "myTool.sayHello":
var params map[string]interface{}
json.Unmarshal(req.Params, ¶ms)
name, ok := params["name"].(string)
if !ok {
name = "World"
}
resp.Result = fmt.Sprintf("Hello, %s from Go MCP Server!", name)
default:
sendError(w, r, -32601, "Method not found", fmt.Sprintf("Method '%s' is not supported.", req.Method))
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(resp); err != nil {
log.Printf("Error sending response: %v\n", err)
}
}
// Helper function: send JSON-RPC error response
func sendError(w http.ResponseWriter, r *http.Request, code int, message string, data interface{}) {
resp := MCPResponse{
Jsonrpc: "2.0",
Error: &MCPError{
Code: code,
Message: message,
Data: data,
},
}
var req MCPRequest
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&req); err == nil {
resp.ID = req.ID
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(resp); err != nil {
log.Printf("Error sending error response: %v\n", err)
}
}
Running the MCP Server
- Save the above code as
mcp_server.go
. - Open your terminal and navigate to the file's directory.
- Run:
go run mcp_server.go
- You should see:
MCP Server listening on http://localhost:8080
, indicating the server started successfully.
How to Integrate with Cursor
Cursor connects to external MCP servers via its "Tools" or "MCP" features. Steps:
- Open Cursor Settings:
- In Cursor, press
Ctrl + ,
(Windows/Linux) orCmd + ,
(macOS) to open settings. - Or via menu:
File
->Settings
->Settings
.
- In Cursor, press
- Search for "MCP" or "Tools":
- In the settings search box, enter "MCP" or "Tools".
- Find an option like "Cursor > Tools: Enable MCP" or "Cursor: MCP Server Endpoints".
- Configure MCP Server Endpoint:
- Cursor usually provides a JSON array to configure MCP server endpoints.
- Find a setting named
cursor.mcpServerEndpoints
or similar. - Click "Edit in settings.json" or "Add Item".
- Add Your Server Address:
- Add your Golang MCP server address to this JSON array. For the above example, the address is
http://localhost:8080
. - Your
settings.json
might look like:
{ // ... other settings ... "cursor.mcpServerEndpoints": [ "http://localhost:8080" ] // ... other settings ... }
- Add your Golang MCP server address to this JSON array. For the above example, the address is
- Restart Cursor:
- Save
settings.json
. - Important: Restart Cursor to apply the settings and let Cursor try to connect to your MCP server.
- Save
- Verify Connection:
- When Cursor starts and tries to connect, you should see output like
Received MCP request: Method=host.initialize, ID="1"
in your Go server terminal. This means Cursor is discovering your tool. - In Cursor's AI Chat panel, try asking about your tool, e.g.:
- "What tools do I have?"
- "Can you say hello?"
- "Use the
myTool.sayHello
tool."
- Expected behavior: If all goes well, Cursor should recognize your
myTool.sayHello
tool and may try to invoke it. Since our server'smyTool.sayHello
method just returns a simple string, you may see a reply like "Hello, World from Go MCP Server!" in Cursor's response (if it tries the tool invocation).
- When Cursor starts and tries to connect, you should see output like
Further Understanding and Limitations
- JSON-RPC 2.0: The MCP protocol is usually based on JSON-RPC 2.0, meaning requests and responses follow a specific JSON format with fields like
jsonrpc
,method
,params
, andid
. Our example includes these basic fields. - Tool Invocation: A complete MCP server must handle tool invocation requests (i.e.,
method
matching your tool name) and execute the corresponding logic based onparams
. In our simplified example,myTool.sayHello
just returns a string, with no real logic. - Asynchronous Operations: Real tools may require time-consuming operations; MCP also supports async handling (e.g., returning a
TaskID
and letting the client query task status later). - Context and Data Flow: MCP allows AI models to access external resources (e.g.,
myResource.currentTime
). A full implementation should return real data based on the AI's request. - Security: In production, consider authentication, authorization, encrypted transmission (HTTPS), etc.
- Error Handling: Robust error handling following JSON-RPC 2.0 error codes is crucial for a healthy MCP server.
Why is this example simplified?
The goal of the MCP protocol is to enable AI models to interact with external systems in complex ways, including:
- Detailed tool definitions: Including tool parameters (usually defined with JSON Schema), return values, side effects, etc.
- Resource data formats: Resource
type
(e.g.,json
,text
,markdown
) andschema
. - Prompt context: Prompts can include dynamic content; the AI needs to know how to fill them in.
- Streaming output and events: For long-running operations, MCP may support streaming output or event notifications.
- Session management: Maintaining state between client and server.
Despite this, the Golang example above gives you a starting point for building a basic MCP server and shows how to establish initial communication with Cursor. To build a fully functional MCP server, you'll need to study the MCP protocol in detail and implement more complex logic based on your specific requirements.