mcp.el

MCP.Pizza Chef: lizqwerscott

mcp.el is a powerful Emacs client designed to interface with the Model Context Protocol (MCP). It facilitates structured communication with MCP servers, including filesystem and generic servers, supporting both asynchronous and synchronous operations. The client offers an extensible tool and prompt system, resource management, and an intuitive interface for managing server lifecycles such as start, stop, and restart. It integrates smoothly with popular Emacs packages like gptel and llm, enhancing the Emacs environment with real-time AI context capabilities. Installation requires Emacs 30 or higher, and configuration is straightforward via Emacs Lisp.

Use This MCP client To

Integrate MCP servers into Emacs workflows Manage MCP server lifecycle within Emacs Enable asynchronous communication with MCP servers Extend Emacs with AI context tools and prompts Use MCP for filesystem data access in Emacs Combine MCP with Emacs AI packages like gptel Customize MCP client behavior via Emacs Lisp

README

MCP.el - Model Context Protocol for Emacs

https://img.shields.io/badge/License-GPLv3-blue.svg

This is an Emacs client for interfacing with MCP, supporting connections to MCP servers.

Features

  • Structured communication with MCP servers
  • Support for filesystem and generic MCP servers
  • Extensible tool and prompt system
  • Asynchronous and synchronous operations
  • Resource management capabilities
  • Intuitive interface for managing server lifecycle (start/stop/restart)
  • Integration with popular Emacs packages (e.g., gptel, llm)

Installation

  1. Install Emacs 30 or higher version
  2. Add the following code to your configuration file ~/.emacs:
    (add-to-list 'load-path "<path-to-mcp.el>")
    (require 'mcp-hub)
        

Usage

Mcp hub

Configuring MCP Servers

(setq mcp-hub-servers
      '(("filesystem" . (:command "npx" :args ("-y" "@modelcontextprotocol/server-filesystem" "/home/lizqwer/MyProject/")))
        ("fetch" . (:command "uvx" :args ("mcp-server-fetch")))
        ("qdrant" . (:url "http://localhost:8000/sse"))
        ("graphlit" . (
                        :command "npx"
                        :args ("-y" "graphlit-mcp-server")
                        :env (
                              :GRAPHLIT_ORGANIZATION_ID "your-organization-id"
                              :GRAPHLIT_ENVIRONMENT_ID "your-environment-id"
                              :GRAPHLIT_JWT_SECRET "your-jwt-secret")))))

You can use mcp-hub-start-all-server to start all MCP servers, such as launching all MCP servers after starting Emacs.

(add-hook 'after-init-hook
          #'mcp-hub-start-all-server)

Managing MCP Servers

Use mcp-hub to launch the server management interface, which will automatically start all configured MCP servers.

mcp-hub

Keymap

keyfunctiondescription
lmcp-hub-view-logView server logs
smcp-hub-start-serverStart server under cursor
kmcp-hub-close-serverStop server under cursor
rmcp-hub-restart-serverRestart server under cursor
Smcp-hub-start-all-serverStart all configured servers
Rmcp-hub-restart-all-serverRestart all configured servers
Kmcp-hub-close-all-serverStop all running servers

use with gptel

A function for registering all MCP tools.

(defun gptel-mcp-register-tool ()
  (interactive)
  (let ((tools (mcp-hub-get-all-tool :asyncp t :categoryp t)))
    (mapcar #'(lambda (tool)
                (apply #'gptel-make-tool
                       tool))
            tools)))

Activate all MCP tools using gptel.

(defun gptel-mcp-use-tool ()
  (interactive)
  (let ((tools (mcp-hub-get-all-tool :asyncp t :categoryp t)))
    (mapcar #'(lambda (tool)
                (let ((path (list (plist-get tool :category)
                                  (plist-get tool :name))))
                  (push (gptel-get-tool path)
                        gptel-tools)))
            tools)))

Request gptel to cease using all mcp tools.

(defun gptel-mcp-close-use-tool ()
  (interactive)
  (let ((tools (mcp-hub-get-all-tool :asyncp t :categoryp t)))
    (mapcar #'(lambda (tool)
                (let ((path (list (plist-get tool :category)
                                  (plist-get tool :name))))
                  (setq gptel-tools
                        (cl-remove-if #'(lambda (tool)
                                          (equal path
                                                 (list (gptel-tool-category tool)
                                                       (gptel-tool-name tool))))
                                      gptel-tools))))
            tools)))

Example filesystem server.

Establish the connection first.

(mcp-connect-server "filesystem" :command "npx" :args '("-y" "@modelcontextprotocol/server-filesystem" "~/Downloads/")
                    :initial-callback
                    #'(lambda (connection)
                        (message "%s connection" (jsonrpc-name connection)))
                    :tools-callback
                    #'(lambda (connection tools)
                        (message "%s tools: %s" (jsonrpc-name connection) tools))
                    :prompts-callback
                    #'(lambda (connection prompts)
                        (message "%s prompts: %s" (jsonrpc-name connection) prompts))
                    :resources-callback
                    #'(lambda (connection resources)
                        (message "%s resources: %s" (jsonrpc-name connection) resources)))

Define the use of tools.

The current text is being tested using the gptel tool branch.Use mcp-make-text-tool to create standard tool call data (Discussions).It is recommended to create tools within the tools-callback or wait for the mcp connect server to complete.

(mcp-make-text-tool "filesystem" "write_file")

This will generate a data structure where the function is an auto-generated synchronous or asynchronous lambda function for accessing the MCP server.

(list :function #'(lambda (&rest args)
                    ;; Synchronous or asynchronous access to the MCP server's Lambda function.
                    )
      :name "write_file"
      :async nil
      :description "Create a new file or completely overwrite an existing file with new content. Use with caution as it will overwrite existing files without warning. Handles text content with proper encoding. Only works within allowed directories."
      :args ((:type "string" :name "path" :description "path")
             (:type "string" :name "content" :description "content"))
      :category "files")

Disconnect from the server.

(mcp-stop-server "filesystem")

Manual function call

Synchronize

(let ((connection (gethash "filesystem" mcp-server-connections)))
  (mcp-call-tool connection "write_file" '(:path "filename or file path" :content "the file content")))

Asynchronous

(let ((connection (gethash "filesystem" mcp-server-connections)))
  (mcp-async-call-tool connection
                       "write_file"
                       '(:path "filename or file path" :content "the file content")
                       #'(lambda (res)
                           ;; handle res
                           (mcp--parse-tool-call-result res))
                       #'(lambda (code message)
                           ;; handle error
                           (format "call %s tool error with %s: %s"
                                   tool-name
                                   code
                                   message))))

Manual get prompt

Since the filesystem lacks prompts, the everything server is used for demonstration.

Synchronize

(let ((connection (gethash "everything" mcp-server-connections)))
  (mcp-get-prompt connection "complex_prompt" '(:temperature "1.0")))

Asynchronous

(let ((connection (gethash "everything" mcp-server-connections)))
  (mcp-async-get-prompt connection
                        "complex_prompt"
                        '(:temperature "1.0")
                        #'(lambda (res)
                            (message "prompt: %s" res))
                        #'(lambda (code message)
                            (message "error call: %s, %s" code message))))

Manual get resources

Since the filesystem lacks resources, the everything server is used for demonstration.

Synchronize

(let ((connection (gethash "everything" mcp-server-connections)))
  (mcp-read-resource connection "test://static/resource/1"))

Asynchronous

(let ((connection (gethash "everything" mcp-server-connections)))
  (mcp-async-read-resource connection "test://static/resource/1"
                           #'(lambda (resource)
                               (message "res: %s" resource))))

Get resource templates

Since the filesystem lacks resources, the everything server is used for demonstration.

(let ((connection (gethash "everything" mcp-server-connections)))
  (mcp-async-list-resource-templates connection
                                     #'(lambda (connection templates)
                                         (message "%s" templates))))

Roadmap

  • [X] HTTP SSE based MCP server connections
  • [ ] mcp marketplace (browser and auto install mcp server)
  • [ ] Simplified integration with other Emacs AI clients
  • [ ] Expanded documentation
  • [ ] Full MCP protocol client implementation

License

This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.

mcp.el FAQ

How do I install mcp.el in Emacs?
Install Emacs 30 or higher, add mcp.el to your load-path, and require 'mcp-hub' in your Emacs config.
Can mcp.el handle both synchronous and asynchronous operations?
Yes, mcp.el supports both synchronous and asynchronous communication with MCP servers for flexible workflows.
How do I configure MCP servers in mcp.el?
Configure servers by setting the 'mcp-hub-servers' variable in your Emacs Lisp configuration with server commands and arguments.
Does mcp.el integrate with other Emacs AI packages?
Yes, it integrates with popular packages like gptel and llm to enhance AI-driven workflows.
Can I manage MCP server lifecycle from within Emacs?
Yes, mcp.el provides an intuitive interface to start, stop, and restart MCP servers directly inside Emacs.
Is mcp.el extensible for custom tools and prompts?
Absolutely, it features an extensible system for adding custom tools and prompts tailored to your needs.
What Emacs version is required for mcp.el?
Emacs version 30 or higher is required to use mcp.el.
Does mcp.el support filesystem MCP servers?
Yes, it supports filesystem MCP servers allowing access to file data within Emacs.
How does mcp.el handle resource management?
It includes resource management capabilities to efficiently handle MCP server connections and data flow.