Skip to content

Conversation

@ravitemer
Copy link
Owner

Overview

Adds native CopilotChat.nvim integration with function calling support, allowing MCP tools and resources to be used directly as CopilotChat functions.

Features

  • Tool Integration: Convert MCP tools to CopilotChat functions with proper schemas
  • Resource Integration: Convert MCP resources to CopilotChat functions for easy access
  • Server Groups: Functions organized by MCP server name for better organization
  • Safe Naming: Conflict resolution for server names (handles cases like "mcp/everything" vs "mcp-everything")
  • Real-time Updates: Automatic updates when MCP servers change
  • Configuration Options: Flexible settings for function conversion and naming

Usage

require("mcphub").setup({
    extensions = {
        copilotchat = {
            enabled = true,
            convert_tools_to_functions = true,     -- Convert MCP tools to functions
            convert_resources_to_functions = true, -- Convert MCP resources to functions  
            add_mcp_prefix = false,                -- Add "mcp_" prefix to function names
        }
    }
})

Then in CopilotChat:

  • Use @server__tool_name to call MCP tools as functions
  • Functions are grouped by server for easy discovery
  • Resources available both as #variables and @functions

Implementation

  • Follows existing mcphub.nvim extension patterns (similar to Avante/CodeCompanion)
  • Uses get_servers() approach for proper conflict handling
  • Async integration with plenary for non-blocking calls
  • Proper cleanup and error handling

Files Added

  • lua/mcphub/extensions/copilotchat/init.lua - Main extension setup
  • lua/mcphub/extensions/copilotchat/functions.lua - Function registration logic
  • doc/extensions/copilotchat.md - Complete documentation

Testing

@deathbeam Would love to get your feedback on this integration! The implementation leverages CopilotChat's native function calling support and should work seamlessly with your recent improvements.

@ravitemer
Copy link
Owner Author

ravitemer commented Jul 29, 2025

Hey @deathbeam! 👋

Two quick notes about the implementation:

Auto-Approval Logic

I've commented out the auto-approval logic in the CopilotChat extension because, as we discussed in #216, CopilotChat needs users to explicitly approve tool calls. This means users are already making deliberate choices when selecting functions, so additional confirmation dialogs might be redundant.

The commented code is still there if we decide to enable it later:

-- TODO: Handle auto-approval logic if possible
-- local result = shared.handle_auto_approval_decision(params)
-- if result.error then
--     error(result.error)
-- end

Resource Templates

I haven't implemented resource templates yet because they require URI parameters to be filled in (e.g., file:///{path} needs a specific path).

Question: How do you think we should handle this in CopilotChat's function interface? Should we:

  1. Skip resource templates entirely for now?
  2. Create functions that prompt for parameters?
  3. Use some other approach for parameter collection?

The infrastructure is ready - just need to figure out the UX for parameter input.

Let me know your thoughts on both points!

@deathbeam
Copy link
Contributor

deathbeam commented Jul 29, 2025

For auto approval, yea as I said currently its very explicit in CopilotChat so for now I guess it makes sense if it just stays commented out.

For resource templates, the issue is mostly parsing the resource template URI to inputSchema for manual input. No need for any custom implementation, as long as there is valid inputSchema, the URI template can be built from it and reconstructed as well.

But I think servers can return resource template as response as well which means the uri part at least needs to be loaded without inputSchema for that scenario regardless.

For example with everything mcp server it has resource template like this:

test://static/resource/{id}

so when that is registered this will get parsed still and recognized when typed manually:

##test://static/resource/11

@deathbeam
Copy link
Contributor

Btw as side note, why do you use double _ as prefix for the servers, I think it looks a bit worse like that and you guarantee uniqueness just with the server name and single dash for example. And it looks better with single dash, for example (github_pull_request etc vs github__pul_request):

image

@ravitemer
Copy link
Owner Author

Thanks for the feedback @deathbeam!

Naming Convention Change ✅

I've updated the naming from server__tool to server_tool as you suggested. Just pushed the change.

My original reasoning for __: I preferred the double underscore for clear demarcation between server and tool names, similar to how our CodeCompanion extension works. But I've changed it to match your preference for better aesthetics.

Resource Templates Issue 🚧

Regarding resource templates, the code you shared at CopilotC-Nvim/CopilotChat.nvim#1204 won't actually work:

-- This won't work for templates
for _, resource in ipairs(resources) do
    local name = resource.server_name .. '_' .. resource.name:lower():gsub(' ', '_'):gsub(':', '')
    chat.config.functions[name] = {
        _mcphub = true,
        uri = resource.uri or resource.uriTemplate,  -- Problem: uriTemplate has {placeholders}
        description = type(resource.description) == 'string' and resource.description or '',
        resolve = function()
            local res, err = access_resource(resource.server_name, resource.uri) -- This tries to access literal "{id}" 
            -- ...
        end,
    }
end

The issue is that resource.uriTemplate contains placeholders like test://static/resource/{id}, and calling access_resource(server_name, "test://static/resource/{id}") will pass the literal {id} to the MCP server instead of a real value.

Resource templates need parameter extraction and schema generation for user input, which requires more complex implementation.

Proposal

If the current integration without resource templates looks good to you, I can merge this PR as-is. Then if you find resource templates useful later, you could open a separate PR to implement them since you're more familiar with CopilotChat's codebase.

What do you think?

@deathbeam
Copy link
Contributor

Ah yea you are right. Yes that makes sense, I will PR the resource templates later this week then probably.

@ravitemer
Copy link
Owner Author

Perfect! Thanks @deathbeam.

I'm going to merge this now. One thing I didn't implement was converting MCP prompts to CopilotChat slash commands (like we do for Avante/CodeCompanion) - not sure if that's possible/useful in CopilotChat, but could be a nice feature for later.

Looking forward to your resource templates PR later this week! 🚀

@ravitemer ravitemer merged commit 9b4d511 into main Jul 29, 2025
5 checks passed
@deathbeam
Copy link
Contributor

Perfect! Thanks @deathbeam.

I'm going to merge this now. One thing I didn't implement was converting MCP prompts to CopilotChat slash commands (like we do for Avante/CodeCompanion) - not sure if that's possible/useful in CopilotChat, but could be a nice feature for later.

Looking forward to your resource templates PR later this week! 🚀

For the MCP prompts, i remember i was looking at it before, but the prompts do not support input like functions do in CopilotChat so at least atm its not rly possible to convert those properly (I also personally dont find that very useful so did not spent much time on it as it has pretty high overlap with resources already)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants