branch: elpa/gptel
commit 3bfe760d0fadb08cf0ffbdc92e85727864ce179d
Author: Karthik Chikmagalur <karthikchikmaga...@gmail.com>
Commit: Karthik Chikmagalur <karthikchikmaga...@gmail.com>

    gptel-integrations: Fix tool-import logic
    
    * gptel-integrations.el (gptel-mcp-connect, gptel-mcp--get-tools):
    Fix issue where all tools from running MCP servers were added even
    if we specify one of them to import tools from in
    `gptel-mcp-connect'.
    
    New function `gptel-mcp--get-tools' works like
    `mcp-hub-get-all-tool', but for a specified list of server names.
    
    TODO: Fix the naming and argument convention across `gptel-mcp-*'
    functions.  Some accept a list of server configurations (as in
    `mcp-hub-servers'), while some accept a list of server names.
    
    (gptel-mcp--activate-tools): Adjust for `gptel-mcp--get-tools'.
    
    (gptel--suffix-mcp-connect, gptel--suffix-mcp-disconnect): Use new
    calling convention of `gptel-mcp-connect' and
    `gptel-mcp-disconnect'.
    
    * README.org (Model Context Protocol (MCP) integration): Mention
    that mcp.el is now available on MELPA.
---
 README.org            |  2 +-
 gptel-integrations.el | 63 +++++++++++++++++++++++++++++++++++----------------
 2 files changed, 45 insertions(+), 20 deletions(-)

diff --git a/README.org b/README.org
index ca3621dc79..c942c736cb 100644
--- a/README.org
+++ b/README.org
@@ -1261,7 +1261,7 @@ The [[https://modelcontextprotocol.io/introduction][Model 
Context Protocol]] (MC
 
 To use MCP servers with gptel, you thus need three pieces:
 
-1. The [[https://github.com/lizqwerscott/mcp.el][mcp.el]] package for Emacs
+1. The [[https://github.com/lizqwerscott/mcp.el][mcp.el]] package for Emacs, 
[[https://melpa.org/#/mcp][available on MELPA]].
 2. MCP servers configured for and running via mcp.el.
 3. gptel and access to an LLM
 
diff --git a/gptel-integrations.el b/gptel-integrations.el
index e4ce47c442..20cea6ce46 100644
--- a/gptel-integrations.el
+++ b/gptel-integrations.el
@@ -42,6 +42,9 @@
 (declare-function mcp-hub-start-all-server "mcp-hub")
 (declare-function mcp-stop-server "mcp")
 (declare-function mcp-hub "mcp-hub")
+(declare-function mcp--status "mcp-hub")
+(declare-function mcp--tools "mcp-hub")
+(declare-function mcp-make-text-tool "mcp-hub")
 (defvar mcp-hub-servers)
 (defvar mcp-server-connections)
 
@@ -89,31 +92,34 @@ Call SERVER-CALLBACK after starting MCP servers."
                     unregistered-servers))
                  (server-active-p
                   (lambda (server) (gethash (car server) 
mcp-server-connections)))
-                 (get-all-tools (lambda () (mcp-hub-get-all-tool :asyncp t 
:categoryp t)))
                  (inactive-servers (cl-remove-if server-active-p servers))
                  (add-all-tools
-                  (lambda ()
+                  (lambda (&optional server-names)
                     "Register and add tools from servers.  Report failures."
-                    (let ((tools (funcall get-all-tools))
+                    (let ((tools (gptel-mcp--get-tools server-names))
                           (now-active (cl-remove-if-not server-active-p 
mcp-hub-servers)))
                       (mapc (lambda (tool) (apply #'gptel-make-tool tool)) 
tools)
                       (gptel-mcp--activate-tools tools)
                       (if-let* ((failed (cl-set-difference inactive-servers 
now-active
                                                            :test #'equal)))
-                          (message "%d/%d server%s failed to start: %s.  Run 
\\[mcp-hub] to investigate."
-                                   (length failed) (length inactive-servers)
-                                   (if (= (length failed) 1) "" "s")
-                                   (mapconcat #'car failed ", "))
-                        (message "Added %d tools from %d MCP server%s: %s"
-                                 (length tools) (length now-active)
-                                 (if (= (length now-active) 1) "" "s")
-                                 (mapconcat #'car now-active ", ")))
+                          (progn
+                            (message "Inactive-before: %S, Now-Active: %S" 
inactive-servers now-active)
+                            (message (substitute-command-keys
+                                      "%d/%d server%s failed to start: %s.  
Run \\[mcp-hub] to investigate.")
+                                     (length failed) (length inactive-servers)
+                                     (if (= (length failed) 1) "" "s")
+                                     (mapconcat #'car failed ", ")))
+                        (let ((added (or server-names (mapcar #'car 
now-active))))
+                          (message "Added %d tools from %d MCP server%s: %s"
+                                   (length tools) (length added)
+                                   (if (= (length added) 1) "" "s")
+                                   (mapconcat #'identity added ", "))))
                       (when (functionp server-callback) (funcall 
server-callback))))))
 
             (if inactive-servers        ;start servers
                 (mcp-hub-start-all-server
                  add-all-tools (mapcar #'car inactive-servers))
-              (funcall add-all-tools)))
+              (funcall add-all-tools (mapcar #'car servers))))
         (message "All MCP tools are already available to gptel!")
         (when (functionp server-callback) (funcall server-callback))))))
 
@@ -170,17 +176,35 @@ If INTERACTIVE is non-nil, query the user about which 
tools to remove."
           (when (gethash (car server) mcp-server-connections)
             (mcp-stop-server (car server))))))))
 
+(defun gptel-mcp--get-tools (&optional server-names)
+  "Return tools from running MCP servers.
+
+SERVER-NAMES is a list of server names to add tools from.  Add tools
+from all connected servers if it is nil."
+  (unless server-names
+    (setq server-names (hash-table-keys mcp-server-connections)))
+  (let ((servers (mapcar (lambda (n) (gethash n mcp-server-connections))
+                         server-names)))
+    (cl-mapcan
+     (lambda (name server)
+       (when (and server (equal (mcp--status server) 'connected))
+         (when-let* ((tools (mcp--tools server))
+                     (tool-names (mapcar #'(lambda (tool) (plist-get tool 
:name)) tools)))
+           (mapcar (lambda (tool-name)
+                     (plist-put (mcp-make-text-tool name tool-name t)
+                                :category (format "mcp-%s" name)))
+                   tool-names))))
+     server-names servers)))
+
 (defun gptel-mcp--activate-tools (&optional tools)
   "Activate TOOLS or all MCP tools in current gptel session."
-  (unless tools (setq tools (mcp-hub-get-all-tool :asyncp t :categoryp t)))
+  (unless tools (setq tools (gptel-mcp--get-tools)))
   (dolist (tool tools)
     (cl-pushnew (gptel-get-tool (list (plist-get tool :category)
                                       (plist-get tool :name)))
                 gptel-tools)))
 
 (with-eval-after-load 'gptel-transient
-  ;; FIXME: If `gptel-mcp-connect' opens mcp-hub, the transient stays open.  I
-  ;; don't know how to fix this.
   (transient-define-suffix gptel--suffix-mcp-connect ()
     "Register tools provided by MCP servers."
     :key "M+"
@@ -189,10 +213,11 @@ If INTERACTIVE is non-nil, query the user about which 
tools to remove."
     (interactive)
     (condition-case err
         (gptel-mcp-connect
-         t (lambda () (when-let* ((transient--prefix)
-                             ((eq (oref transient--prefix command)
-                                  'gptel-tools)))
-                   (transient-setup 'gptel-tools))))
+         nil (lambda () (when-let* ((transient--prefix)
+                               ((eq (oref transient--prefix command)
+                                    'gptel-tools)))
+                     (transient-setup 'gptel-tools)))
+         t)
       (user-error (message "%s" (cadr err))))
     (transient-setup))
 

Reply via email to