经 AI Skill Hub 精选评估,Emacs Lisp实现的Model Context Protocol工具 获评「推荐使用」。这款MCP工具在功能完整性、社区活跃度和易用性方面表现出色,AI 评分 7.5 分,适合有一定技术背景的用户使用。
Emacs Lisp实现的Model Context Protocol工具 是一款遵循 MCP(Model Context Protocol)标准协议的 AI 工具扩展。通过 MCP 协议,它可以让 Claude、Cursor 等主流 AI 客户端直接访问和操作外部工具、数据源和服务,实现 AI 能力的无缝扩展。无论是文件操作、数据库查询还是 API 调用,都可以通过自然语言在 AI 对话中直接触发,极大提升生产效率。
Emacs Lisp实现的Model Context Protocol工具 是一款遵循 MCP(Model Context Protocol)标准协议的 AI 工具扩展。通过 MCP 协议,它可以让 Claude、Cursor 等主流 AI 客户端直接访问和操作外部工具、数据源和服务,实现 AI 能力的无缝扩展。无论是文件操作、数据库查询还是 API 调用,都可以通过自然语言在 AI 对话中直接触发,极大提升生产效率。
# 方式一:通过 Claude Code CLI 一键安装
claude skill install https://github.com/laurynas-biveinis/mcp-server-lib.el
# 方式二:手动配置 claude_desktop_config.json
{
"mcpServers": {
"emacs-lisp---model-context-protocol--": {
"command": "npx",
"args": ["-y", "mcp-server-lib.el"]
}
}
}
# 配置文件位置
# macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
# Windows: %APPDATA%/Claude/claude_desktop_config.json
# 安装后在 Claude 对话中直接使用 # 示例: 用户: 请帮我用 Emacs Lisp实现的Model Context Protocol工具 执行以下任务... Claude: [自动调用 Emacs Lisp实现的Model Context Protocol工具 MCP 工具处理请求] # 查看可用工具列表 # 在 Claude 中输入:"列出所有可用的 MCP 工具"
// claude_desktop_config.json 配置示例
{
"mcpServers": {
"emacs_lisp___model_context_protocol__": {
"command": "npx",
"args": ["-y", "mcp-server-lib.el"],
"env": {
// "API_KEY": "your-api-key-here"
}
}
}
}
// 保存后重启 Claude Desktop 生效
#+TITLE: mcp-server-lib.el - Model Context Protocol Server Library for Emacs Lisp
[[https://github.com/laurynas-biveinis/mcp-server-lib.el/actions/workflows/elisp-test.yml][https://github.com/laurynas-biveinis/mcp-server-lib.el/actions/workflows/elisp-test.yml/badge.svg]] [[https://github.com/laurynas-biveinis/mcp-server-lib.el/actions/workflows/linter.yml][https://github.com/laurynas-biveinis/mcp-server-lib.el/actions/workflows/linter.yml/badge.svg]] [[https://melpa.org/#/mcp-server-lib][https://melpa.org/packages/mcp-server-lib-badge.svg]] [[https://stable.melpa.org/#/mcp-server-lib][file:https://stable.melpa.org/packages/mcp-server-lib-badge.svg]]
=mcp-server-lib.el= is a library for building [[https://modelcontextprotocol.io/][Model Context Protocol]] (MCP) servers in Emacs Lisp. It provides the infrastructure for Emacs packages to expose their functionality as tools and resources to Large Language Models.
From [[https://melpa.org/#/mcp-server-lib][MELPA]] or [[https://stable.melpa.org/#/mcp-server-lib][MELPA Stable]]:
=M-x package-install RET mcp-server-lib RET=
If you're using an MCP server built with this library:
Available commands: - =M-x mcp-server-lib-start= - Start the MCP server - =M-x mcp-server-lib-stop= - Stop the MCP server - =M-x mcp-server-lib-describe-setup= - View registered tools and resources with usage statistics - =M-x mcp-server-lib-show-metrics= - View usage metrics - =M-x mcp-server-lib-uninstall= - Remove the stdio script
To build your own MCP server, see [[https://github.com/laurynas-biveinis/elisp-dev-mcp][elisp-dev-mcp]] for a complete example.
** Client Registration
Register your MCP server with a client using the stdio script:
#+BEGIN_EXAMPLE claude mcp add -s user -t stdio your-server -- ~/.emacs.d/emacs-mcp-stdio.sh \ --init-function=your-init-func --stop-function=your-stop-func #+END_EXAMPLE
Script options: - =--init-function=NAME= - Emacs function to call on startup - =--stop-function=NAME= - Emacs function to call on shutdown - =--socket=PATH= - Custom Emacs server socket (optional) - =--server-id=ID= - Explicit server identifier (optional, will become mandatory in the future)
For debugging, set =EMACS_MCP_DEBUG_LOG= to a file path.
** API Reference
*** Registration
Use =mcp-server-lib-register-server= to declare a server's metadata, tools, and resources in a single call. Within one call, duplicate tool =:id=s or resource URIs are rejected.
#+begin_src elisp (mcp-server-lib-register-server :id "my-server" ; optional, defaults to "default" :name "My Server" ; optional, defaults to :id :version "1.2.0" ; optional, defaults to "1.0.0" :instructions "Cite source resource URIs when quoting their contents." ; optional :tools (list (list #'my-list-files :id "list-files" :description "Lists all files" :title "List Files" ; optional :read-only t) ; optional (list #'update-todo-state :id "update-todo" :description "Update task TODO state")) :resources (list (list "resource://uri" (lambda () "resource content") :name "Resource Name" :description "What this provides" ; optional :mime-type "text/plain") ; optional ;; Template URIs (containing {var}) are detected automatically (list "org://{filename}" (lambda (params) (with-temp-buffer (insert-file-contents (alist-get "filename" params nil nil #'string=)) (buffer-string))) :name "Org file content"))) #+end_src
Each entry is registered with reference counting, so two bundled calls with overlapping entries increment ref-counts and need two =mcp-server-lib-unregister-server= calls to fully tear down.
Every =mcp-server-lib-register-server= call creates or bumps a per-server metadata record, so each successful call must be paired with =mcp-server-lib-unregister-server= for clean teardown -- including calls that supply no =:tools=, =:resources=, or =:instructions=, and calls that rely on the default ="default"= =:id=.
The optional =:name= (defaulting to =:id=) and =:version= (defaulting to ="1.0.0"=) are reported as =serverInfo.name= and =serverInfo.version= in the server's =initialize= response. These describe the server implementation; =:version= is the server's own version, distinct from the MCP =protocolVersion=. The =:id=, in contrast, is an internal routing key that selects the server's tools and resources and is never sent to the client. A server configured only through the obsolete =mcp-server-lib-register-tool= / =mcp-server-lib-register-resource= API has no metadata record, so its =serverInfo= reports the =server-id= as the name and the default version.
The =:instructions= string is emitted in the server's =initialize= response (per the MCP protocol spec), giving the client's LLM guidance on how to use the server's tools and resources.
**** Updating an existing tool or resource
Re-registration under an existing key keeps the original spec; the new handler and properties are discarded and only the ref-count is bumped. This first-writer-wins policy keeps overlapping tools/resources stable for as long as any caller still holds a reference. To update a handler or properties, tear down with =mcp-server-lib-unregister-server= first and then re-register. =:name=, =:version=, and =:instructions= are exceptions (last-writer-wins) because they live on the server record with no per-key ref-count: a re-registration that supplies one of these keys overwrites the stored value, while omitting it leaves the previous value intact.
*** Tool Handlers
Tool handler functions:
#+begin_src elisp ;; Tool handler with no parameters (defun my-list-files () "List files in the current directory." (mcp-server-lib-with-error-handling (mapconcat #'identity (directory-files ".") "\n")))
;; Tool handler with one parameter (defun my-handler (location) "Get weather for LOCATION.
MCP Parameters: location - city, address, or coordinates" (mcp-server-lib-with-error-handling ;; Your implementation ))
;; Tool handler with multiple parameters (defun update-todo-state (resource-uri current-state new-state) "Update TODO state of a task.
MCP Parameters: resource-uri - URI of the task to update current-state - Current TODO state (or empty string) new-state - New TODO state to set" (mcp-server-lib-with-error-handling ;; Direct access to parameters, no alist-get needed (message "Updating %s from %s to %s" resource-uri current-state new-state))) #+end_src
**** MCP Parameters Format
Parameter descriptions in tool handler docstrings follow an indentation-based format:
Example with multi-line parameter descriptions:
#+begin_src elisp (defun fetch-content (url timeout) "Fetch content from a URL.
MCP Parameters: url - web address to fetch Supports http, https, and file protocols Must be a valid URI timeout - seconds to wait before giving up Use 0 for no timeout" (mcp-server-lib-with-error-handling ;; Implementation )) #+end_src
These docstring descriptions are the single source for the tool's =inputSchema=; do not repeat them in the tool =:description= (see below).
Tools can have zero, one, or multiple parameters. When a tool has multiple parameters, the JSON object fields from the client are automatically mapped to the function parameters by name. JSON field names must match the Lisp parameter names exactly. Tools do not support =&rest= parameters.
Tool handlers must return strings or =nil= (which is converted to an empty string). Other return types will cause an "Invalid Params" error.
If a tool cannot complete its operation successfully, it should use =mcp-server-lib-tool-throw= for throwing an error or the implementation should be wrapped with =mcp-server-lib-with-error-handling=.
Tool entry properties accepted in =:tools=: - =:id= (required) - String identifier for the tool (e.g., ="list-files"=) - =:description= (required) - String describing what the tool does and when to use it. Describe the tool as a whole; do not restate individual parameters here. Per-parameter descriptions belong solely in the handler's =MCP Parameters:= docstring block, from which they are extracted into the tool's =inputSchema=. The client receives both, so repeating parameter text in =:description= is redundant and risks drift. - =:title= - User-friendly display name - =:read-only= - Set to =t= if tool doesn't modify state
Unknown or duplicate property keys signal an error at registration time.
*** Resource Handlers
The library uses a unified API for both static and templated resources. The presence of ={variable}= syntax in a URI automatically determines whether the entry is a static resource or a template.
Resource handlers go in the =:resources= list of =mcp-server-lib-register-server=; each entry is =(URI HANDLER &rest PROPERTIES)= so the handler is the second element.
#+begin_src elisp ;; Static resource (no variables): handler takes no arguments (lambda () "resource content")
;; Template resource with simple variable: handler takes params alist (lambda (params) (with-temp-buffer (insert-file-contents (alist-get "filename" params nil nil #'string=)) (buffer-string)))
;; Template with multiple variables (including {+var} for reserved expansion) (lambda (params) (let ((file (alist-get "filename" params nil nil #'string=)) (path (alist-get "path" params nil nil #'string=))) ;; path can contain slashes with {+path} (org-get-headline-content file path))) #+end_src
Resource entry properties accepted in =:resources=: - The first list element is the =URI= (required string) - The second list element is the =handler= function (required) - =:name= (required) - Human-readable name - =:description= - Description of the resource - =:mime-type= - MIME type (default: ="text/plain"=)
Unknown or duplicate property keys signal an error at registration time.
Supported template syntax (RFC 6570 subset): - ={variable}= - Simple variable expansion - ={+variable}= - Reserved expansion (allows slashes)
Direct resources take precedence over templates when both match a URI.
*** Resource Error Handling
Resource handlers can signal specific JSON-RPC error codes to provide meaningful error information to clients:
#+begin_src elisp ;; Signal that client provided invalid parameters (defun my-file-resource-handler (params) (let ((file (alist-get "filename" params nil nil #'string=))) (unless (file-exists-p file) (mcp-server-lib-resource-signal-error mcp-server-lib-jsonrpc-error-invalid-params (format "File not found: %s" file))) (with-temp-buffer (insert-file-contents file) (buffer-string))))
;; Signal an internal server error (defun my-database-resource-handler () (unless (database-connected-p) (mcp-server-lib-resource-signal-error mcp-server-lib-jsonrpc-error-internal "Database connection unavailable")) (query-database)) #+end_src
Available error codes: - =mcp-server-lib-jsonrpc-error-invalid-params= (-32602): Client provided invalid parameters, resource not found - =mcp-server-lib-jsonrpc-error-internal= (-32603): Server-side processing error
It is also possible to use regular =error= or =signal= calls, which would return internal error (-32603).
*** Working with Resource Templates
Resource template handlers receive extracted parameters as an alist. These parameters are matched from the URI but not automatically decoded - if you're working with file paths that might contain special characters, you'll want to decode them:
#+begin_src elisp (mcp-server-lib-register-server :id "my-server" :resources (list (list "file://{path}" (lambda (params) (let ((path (alist-get "path" params nil nil #'string=))) ;; Decode if needed for filesystem access (with-temp-buffer (insert-file-contents (url-unhex-string path)) (buffer-string)))) :name "File reader"))) #+end_src
Variable names in templates follow simple rules - stick to letters, numbers, and underscores. The URI scheme (like =file://= or =org://=) needs to be a valid URI scheme starting with a letter. URI schemes are case-insensitive per RFC 3986, so =HTTP://example.com= will match a template registered as =http://{domain}=.
When multiple templates could match the same URI, which template is selected is undefined and depends on implementation details. Avoid registering overlapping templates.
Templates can match empty values too - =org://= will match =org://{filename}= with an empty filename.
Literal segments in templates must match exactly - =test://items/{id}= will match =test://items/123= but not =test://item/123=.
The implementation uses non-greedy (first-match) behavior when matching variables. For example, =test://{name}.txt= matching =test://file.config.txt= extracts =name="file.config"=, not =name="file.config.txt"=.
*** Unregistration
To tear down everything a package registered with a given server-id (for example, in a =-disable= function), call =mcp-server-lib-unregister-server=. This is the symmetric counterpart of =mcp-server-lib-register-server=:
#+begin_src elisp (defun my-mcp-disable () (mcp-server-lib-unregister-server "my-server")) #+end_src
Each registered entry — tools, resources, templates, and the per-server metadata record holding optional =:instructions= — has its reference count decremented exactly once. Entries whose count was one are fully removed; entries with a higher count (e.g. from nested test fixtures) remain at the reduced count. =:instructions= is never reverted by =mcp-server-lib-unregister-server=; only =mcp-server-lib-register-server= updates it. Calling =mcp-server-lib-unregister-server= on an unknown server-id is a silent no-op. Pass ="default"= explicitly to operate on the default server.
*** Deprecated APIs
The individual registration / unregistration functions are obsolete as of 0.3.0 in favor of the bundled =mcp-server-lib-register-server= / =mcp-server-lib-unregister-server= form:
The migration is per-fixture, not per-call: there is no per-key replacement for =mcp-server-lib-unregister-tool= or =mcp-server-lib-unregister-resource=. Pair each bundled =mcp-server-lib-register-server= with one =mcp-server-lib-unregister-server= (which tears down every entry the bundled call registered).
The deprecated functions continue to work; references to them produce byte-compile warnings.
The two API styles can be mixed during migration. =mcp-server-lib-unregister-server= tears down per-kind entries regardless of how they were registered, so it also clears tools and resources registered via the obsolete =mcp-server-lib-register-tool= / =mcp-server-lib-register-resource=. The per-server metadata record, however, is only created by =mcp-server-lib-register-server=; the per-key =mcp-server-lib-unregister-tool= / =mcp-server-lib-unregister-resource= do not touch it, so a per-key legacy unregister after a bundled register leaves the record (including any =:instructions=) in place until =mcp-server-lib-unregister-server= clears it.
*** Resource Lists
When clients request the resource list, direct resources appear with a =uri= field while templates show up with a =uriTemplate= field. This helps clients distinguish between static resources and dynamic patterns they can use.
*** Constants
=mcp-server-lib-protocol-version= - The MCP protocol version supported by this server ("2025-03-26")
=mcp-server-lib-default-server-version= - Default =serverInfo.version= reported when a server registers without =:version= ("1.0.0")
*** Utility Functions
For testing and debugging:
#+begin_src elisp ;; Create JSON-RPC requests (mcp-server-lib-create-tools-list-request &optional id) (mcp-server-lib-create-tools-call-request tool-name &optional id args) (mcp-server-lib-create-resources-list-request &optional id) (mcp-server-lib-create-resources-read-request uri &optional id)
;; Process requests and get parsed response (mcp-server-lib-process-jsonrpc-parsed request server-id)
;; Server management (mcp-server-lib-start) (mcp-server-lib-stop)
;; Query whether a server-id has a registered metadata record (mcp-server-lib-server-registered-p server-id)
;; Path where mcp-server-lib-install places emacs-mcp-stdio.sh (mcp-server-lib-installed-script-path) #+end_src
*** Test Utilities
The =mcp-server-lib-ert= module provides utilities for writing ERT tests for MCP servers:
**** Server Context Variable
Test helper functions use the dynamic variable =mcp-server-lib-ert-server-id= to determine which server to operate on. Child packages testing a single server should set this once at the top of their test file:
#+begin_src elisp ;; At the top of your test file (setq mcp-server-lib-ert-server-id "my-mcp-server") #+end_src
**** Test Helper Functions
#+begin_src elisp ;; Track metrics changes during test execution (mcp-server-lib-ert-with-metrics-tracking ((method expected-calls expected-errors) ...) ;; Test code here )
;; Example: Verify a method is called once with no errors (mcp-server-lib-ert-with-metrics-tracking (("tools/list" 1 0)) ;; Code that should call tools/list once (mcp-server-lib-process-jsonrpc-parsed (mcp-server-lib-create-tools-list-request) "example server"))
;; Simplified syntax for verifying successful single method calls (mcp-server-lib-ert-verify-req-success "tools/list" (mcp-server-lib-process-jsonrpc-parsed (mcp-server-lib-create-tools-list-request) "example server"))
;; Process a request and get the successful result (let* ((request (mcp-server-lib-create-tools-list-request)) (tools (mcp-server-lib-ert-get-success-result "tools/list" request))) ;; tools contains the result field from the response (should (arrayp tools)))
;; High-level tool testing helper - simplifies tool calls ;; This function combines request creation, processing, metrics verification, ;; and text extraction into a single call (let* ((params '(("name" . "John") ("greeting" . "Hello"))) (result (mcp-server-lib-ert-call-tool "greet-user" params))) (should (string= "Hello, John!" result)))
;; Get resource list (convenience function) (let ((resources (mcp-server-lib-ert-get-resource-list))) (should (= 2 (length resources))) (should (string= "test://resource1" (alist-get 'uri (aref resources 0)))))
;; Check error response structure (mcp-server-lib-ert-check-error-object response -32601 "Method not found")
;; Verify resource read succeeds with expected fields (mcp-server-lib-ert-verify-resource-read "test://resource1" '((uri . "test://resource1") (mimeType . "text/plain") (text . "test result")))
;; Run tests with MCP server (mcp-server-lib-ert-with-server :tools nil :resources nil ;; Server is started, initialized, and will be stopped after body (let ((response (mcp-server-lib-process-jsonrpc-parsed (json-encode '(("jsonrpc" . "2.0") ("method" . "tools/list") ("id" . 1))) "example server"))) (should-not (alist-get 'error response)))) #+end_src
*** JSON-RPC Error Constants
The library provides public constants for standard JSON-RPC 2.0 error codes:
#+begin_src elisp mcp-server-lib-jsonrpc-error-parse ; -32700 Parse Error mcp-server-lib-jsonrpc-error-invalid-request ; -32600 Invalid Request mcp-server-lib-jsonrpc-error-method-not-found ; -32601 Method Not Found mcp-server-lib-jsonrpc-error-invalid-params ; -32602 Invalid Params mcp-server-lib-jsonrpc-error-internal ; -32603 Internal Error #+end_src
These constants can be used when checking error responses in tests:
#+begin_src elisp (mcp-server-lib-ert-check-error-object response mcp-server-lib-jsonrpc-error-method-not-found "Method not found") #+end_src
*** Debugging
Enable JSON-RPC message logging:
#+begin_src elisp (setq mcp-server-lib-log-io t) ; Log to mcp-server-lib-log buffer #+end_src
View usage metrics:
#+begin_src elisp M-x mcp-server-lib-show-metrics M-x mcp-server-lib-reset-metrics #+end_src
** Customization
To install the script to a different location:
#+begin_src elisp (setq mcp-server-lib-install-directory "/path/to/directory") #+end_src
This project is licensed under the GNU General Public License v3.0 (GPLv3) - see the LICENSE file for details.
该项目提供了Emacs Lisp实现的Model Context Protocol工具,方便开发者使用和扩展,值得关注。
AI Skill Hub 为第三方内容聚合平台,本页面信息基于公开数据整理,不对工具功能和质量作任何法律背书。
建议在沙箱或测试环境中充分验证后,再部署至生产环境,并做好必要的安全评估。
⚠️ GPL 3.0 — 强 Copyleft,衍生作品须开源,含专利保护条款,不可闭源使用。
AI Skill Hub 点评:Emacs Lisp实现的Model Context Protocol工具 的核心功能完整,质量良好。对于Claude Desktop / Claude Code 用户来说,这是一个值得纳入个人工具库的选择。建议先在非生产环境试用,再逐步推广。
| 原始名称 | mcp-server-lib-el |
| 原始描述 | 开源MCP工具:Emacs Lisp implementation of the Model Context Protocol。⭐44 · Emacs Lisp |
| Topics | mcpemacs lisp |
| GitHub | https://github.com/laurynas-biveinis/mcp-server-lib.el |
| License | GPL-3.0 |
| 语言 | Emacs Lisp |
收录时间:2026-06-13 · 更新时间:2026-06-13 · License:GPL-3.0 · AI Skill Hub 不对第三方内容的准确性作法律背书。
选择 Agent 类型,复制安装指令后粘贴到对应客户端