feat: implement dynamic MCP tool discovery with shared server architecture
- Replace hardcoded tool lists with dynamic discovery via MCP tools/list - Move MCPServerManager to application supervision tree for resource sharing - Eliminate duplicate MCP server instances (one shared instance per server type) - Add automatic tool refresh when servers restart - Implement conditional VS Code tool loading based on module availability - Add comprehensive test suite for dynamic discovery - Update documentation with architecture improvements Benefits: - Full MCP protocol compliance - Massive resource savings (shared servers vs per-agent instances) - Zero maintenance overhead for tool list synchronization - Automatic adaptation to server changes - Improved reliability and performance Closes: Dynamic tool discovery implementation Fixes: Multiple MCP server instance resource waste
This commit is contained in:
@@ -23,6 +23,9 @@ defmodule AgentCoordinator.Application do
|
||||
# Task registry with NATS integration (conditionally add persistence)
|
||||
{AgentCoordinator.TaskRegistry, nats: if(enable_persistence, do: nats_config(), else: nil)},
|
||||
|
||||
# MCP Server Manager (manages external MCP servers)
|
||||
{AgentCoordinator.MCPServerManager, config_file: Application.get_env(:agent_coordinator, :mcp_config_file, "mcp_servers.json")},
|
||||
|
||||
# MCP server
|
||||
AgentCoordinator.MCPServer,
|
||||
|
||||
|
||||
@@ -51,6 +51,13 @@ defmodule AgentCoordinator.MCPServerManager do
|
||||
GenServer.call(__MODULE__, {:restart_server, server_name})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Refresh tool registry by re-discovering tools from all servers
|
||||
"""
|
||||
def refresh_tools do
|
||||
GenServer.call(__MODULE__, :refresh_tools)
|
||||
end
|
||||
|
||||
# Server callbacks
|
||||
|
||||
def init(opts) do
|
||||
@@ -176,6 +183,17 @@ defmodule AgentCoordinator.MCPServerManager do
|
||||
end
|
||||
end
|
||||
|
||||
def handle_call(:refresh_tools, _from, state) do
|
||||
# Re-discover tools from all running servers
|
||||
updated_state = rediscover_all_tools(state)
|
||||
|
||||
all_tools = get_coordinator_tools() ++ (Map.values(updated_state.tool_registry) |> List.flatten())
|
||||
|
||||
Logger.info("Refreshed tool registry: found #{length(all_tools)} total tools")
|
||||
|
||||
{:reply, {:ok, length(all_tools)}, updated_state}
|
||||
end
|
||||
|
||||
def handle_info({:DOWN, _ref, :port, port, reason}, state) do
|
||||
# Handle server port death
|
||||
case find_server_by_port(port, state.servers) do
|
||||
@@ -598,9 +616,44 @@ defmodule AgentCoordinator.MCPServerManager do
|
||||
%{state | tool_registry: new_registry}
|
||||
end
|
||||
|
||||
defp rediscover_all_tools(state) do
|
||||
# Re-query all running servers for their current tools
|
||||
updated_servers =
|
||||
Enum.reduce(state.servers, state.servers, fn {name, server_info}, acc ->
|
||||
# Check if server is alive (handle both PID and Port)
|
||||
server_alive = case server_info.pid do
|
||||
nil -> false
|
||||
pid when is_pid(pid) -> Process.alive?(pid)
|
||||
port when is_port(port) -> Port.info(port) != nil
|
||||
_ -> false
|
||||
end
|
||||
|
||||
if server_alive do
|
||||
case get_server_tools(server_info) do
|
||||
{:ok, new_tools} ->
|
||||
Logger.debug("Rediscovered #{length(new_tools)} tools from #{name}")
|
||||
Map.put(acc, name, %{server_info | tools: new_tools})
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.warning("Failed to rediscover tools from #{name}: #{inspect(reason)}")
|
||||
acc
|
||||
end
|
||||
else
|
||||
Logger.warning("Server #{name} is not alive, skipping tool rediscovery")
|
||||
acc
|
||||
end
|
||||
end)
|
||||
|
||||
# Update state with new server info and refresh tool registry
|
||||
new_state = %{state | servers: updated_servers}
|
||||
refresh_tool_registry(new_state)
|
||||
end
|
||||
|
||||
defp find_tool_server(tool_name, state) do
|
||||
# Check Agent Coordinator tools first
|
||||
if tool_name in get_coordinator_tool_names() do
|
||||
# Check all tool registries (both coordinator and external servers)
|
||||
# Start with coordinator tools
|
||||
coordinator_tools = get_coordinator_tools()
|
||||
if Enum.any?(coordinator_tools, fn tool -> tool["name"] == tool_name end) do
|
||||
{:coordinator, tool_name}
|
||||
else
|
||||
# Check external servers
|
||||
@@ -634,6 +687,10 @@ defmodule AgentCoordinator.MCPServerManager do
|
||||
"capabilities" => %{
|
||||
"type" => "array",
|
||||
"items" => %{"type" => "string"}
|
||||
},
|
||||
"metadata" => %{
|
||||
"type" => "object",
|
||||
"description" => "Optional metadata about the agent (e.g., client_type, session_id)"
|
||||
}
|
||||
},
|
||||
"required" => ["name", "capabilities"]
|
||||
@@ -703,31 +760,39 @@ defmodule AgentCoordinator.MCPServerManager do
|
||||
}
|
||||
]
|
||||
|
||||
# Get VS Code tools
|
||||
vscode_tools = AgentCoordinator.VSCodeToolProvider.get_tools()
|
||||
# Get VS Code tools only if VS Code functionality is available
|
||||
vscode_tools = try do
|
||||
if Code.ensure_loaded?(AgentCoordinator.VSCodeToolProvider) do
|
||||
AgentCoordinator.VSCodeToolProvider.get_tools()
|
||||
else
|
||||
Logger.debug("VS Code tools not available - module not loaded")
|
||||
[]
|
||||
end
|
||||
rescue
|
||||
_ ->
|
||||
Logger.debug("VS Code tools not available - error loading")
|
||||
[]
|
||||
end
|
||||
|
||||
# Combine all coordinator tools
|
||||
coordinator_native_tools ++ vscode_tools
|
||||
end
|
||||
|
||||
defp get_coordinator_tool_names do
|
||||
# Agent Coordinator native tools
|
||||
coordinator_native = ~w[register_agent create_task get_next_task complete_task get_task_board heartbeat]
|
||||
|
||||
# VS Code tool names
|
||||
vscode_tools = AgentCoordinator.VSCodeToolProvider.get_tools()
|
||||
|> Enum.map(fn tool -> tool["name"] end)
|
||||
|
||||
coordinator_native ++ vscode_tools
|
||||
end
|
||||
# Removed get_coordinator_tool_names - now using dynamic tool discovery
|
||||
|
||||
defp handle_coordinator_tool(tool_name, arguments, agent_context) do
|
||||
# Route to existing Agent Coordinator functionality or VS Code tools
|
||||
case tool_name do
|
||||
"register_agent" ->
|
||||
opts = case arguments["metadata"] do
|
||||
nil -> []
|
||||
metadata -> [metadata: metadata]
|
||||
end
|
||||
|
||||
AgentCoordinator.TaskRegistry.register_agent(
|
||||
arguments["name"],
|
||||
arguments["capabilities"]
|
||||
arguments["capabilities"],
|
||||
opts
|
||||
)
|
||||
|
||||
"create_task" ->
|
||||
|
||||
@@ -55,6 +55,14 @@ defmodule AgentCoordinator.TaskRegistry do
|
||||
GenServer.call(__MODULE__, {:get_agent_current_task, agent_id})
|
||||
end
|
||||
|
||||
def get_agent(agent_id) do
|
||||
GenServer.call(__MODULE__, {:get_agent, agent_id})
|
||||
end
|
||||
|
||||
def get_agent_by_name(agent_name) do
|
||||
GenServer.call(__MODULE__, {:get_agent_by_name, agent_name})
|
||||
end
|
||||
|
||||
def update_task_activity(task_id, tool_name, arguments) do
|
||||
GenServer.call(__MODULE__, {:update_task_activity, task_id, tool_name, arguments})
|
||||
end
|
||||
@@ -75,8 +83,8 @@ defmodule AgentCoordinator.TaskRegistry do
|
||||
GenServer.call(__MODULE__, :get_task_board)
|
||||
end
|
||||
|
||||
def register_agent(name, capabilities) do
|
||||
agent = Agent.new(name, capabilities)
|
||||
def register_agent(name, capabilities, opts \\ []) do
|
||||
agent = Agent.new(name, capabilities, opts)
|
||||
GenServer.call(__MODULE__, {:register_agent, agent})
|
||||
end
|
||||
|
||||
@@ -272,6 +280,24 @@ defmodule AgentCoordinator.TaskRegistry do
|
||||
end
|
||||
end
|
||||
|
||||
def handle_call({:get_agent, agent_id}, _from, state) do
|
||||
case Map.get(state.agents, agent_id) do
|
||||
nil ->
|
||||
{:reply, {:error, :not_found}, state}
|
||||
agent ->
|
||||
{:reply, {:ok, agent}, state}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_call({:get_agent_by_name, agent_name}, _from, state) do
|
||||
case Enum.find(state.agents, fn {_id, agent} -> agent.name == agent_name end) do
|
||||
nil ->
|
||||
{:reply, {:error, :not_found}, state}
|
||||
{_id, agent} ->
|
||||
{:reply, {:ok, agent}, state}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_call({:update_task_activity, task_id, tool_name, arguments}, _from, state) do
|
||||
# Update task with latest activity
|
||||
# This could store activity logs or update task metadata
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
defmodule AgentCoordinator.VSCodePermissions do
|
||||
@moduledoc """
|
||||
Manages permissions for VS Code tool access.
|
||||
|
||||
|
||||
Provides fine-grained permission control for agents accessing VS Code tools,
|
||||
ensuring security and preventing unauthorized operations.
|
||||
"""
|
||||
@@ -10,7 +10,7 @@ defmodule AgentCoordinator.VSCodePermissions do
|
||||
|
||||
@permission_levels %{
|
||||
read_only: 1,
|
||||
editor: 2,
|
||||
editor: 2,
|
||||
filesystem: 3,
|
||||
terminal: 4,
|
||||
git: 5,
|
||||
@@ -21,7 +21,7 @@ defmodule AgentCoordinator.VSCodePermissions do
|
||||
# File Operations (filesystem level)
|
||||
"vscode_read_file" => :read_only,
|
||||
"vscode_write_file" => :filesystem,
|
||||
"vscode_create_file" => :filesystem,
|
||||
"vscode_create_file" => :filesystem,
|
||||
"vscode_delete_file" => :filesystem,
|
||||
"vscode_list_directory" => :read_only,
|
||||
"vscode_get_workspace_folders" => :read_only,
|
||||
@@ -35,34 +35,34 @@ defmodule AgentCoordinator.VSCodePermissions do
|
||||
# Command Operations (varies by command)
|
||||
"vscode_run_command" => :admin, # Default to admin, will check specific commands
|
||||
|
||||
# User Communication
|
||||
# User Communication
|
||||
"vscode_show_message" => :read_only
|
||||
}
|
||||
|
||||
@whitelisted_commands [
|
||||
# Safe editor commands
|
||||
"editor.action.formatDocument",
|
||||
"editor.action.formatSelection",
|
||||
"editor.action.formatSelection",
|
||||
"editor.action.organizeImports",
|
||||
"editor.fold",
|
||||
"editor.unfold",
|
||||
"editor.toggleFold",
|
||||
|
||||
|
||||
# Safe navigation commands
|
||||
"workbench.action.navigateBack",
|
||||
"workbench.action.navigateForward",
|
||||
"workbench.action.gotoLine",
|
||||
"workbench.action.quickOpen",
|
||||
"workbench.action.showCommands",
|
||||
|
||||
|
||||
# Safe file operations
|
||||
"workbench.action.files.save",
|
||||
"workbench.action.files.saveAll",
|
||||
"workbench.explorer.refreshExplorer",
|
||||
|
||||
|
||||
# Language service operations
|
||||
"editor.action.goToDeclaration",
|
||||
"editor.action.goToDefinition",
|
||||
"editor.action.goToDefinition",
|
||||
"editor.action.goToReferences",
|
||||
"editor.action.rename",
|
||||
"editor.action.quickFix"
|
||||
@@ -70,25 +70,25 @@ defmodule AgentCoordinator.VSCodePermissions do
|
||||
|
||||
@doc """
|
||||
Check if an agent has permission to use a specific VS Code tool.
|
||||
|
||||
|
||||
Returns {:ok, permission_level} if allowed, {:error, reason} if denied.
|
||||
"""
|
||||
def check_permission(context, tool_name, args) do
|
||||
agent_id = context[:agent_id] || "unknown"
|
||||
|
||||
|
||||
# Get required permission level for this tool
|
||||
required_level = get_required_permission(tool_name, args)
|
||||
|
||||
|
||||
# Get agent's permission level
|
||||
agent_level = get_agent_permission_level(agent_id)
|
||||
|
||||
|
||||
# Check if agent has sufficient permissions
|
||||
if permission_sufficient?(agent_level, required_level) do
|
||||
# Additional checks for specific tools
|
||||
case additional_checks(tool_name, args, context) do
|
||||
:ok ->
|
||||
:ok ->
|
||||
{:ok, required_level}
|
||||
{:error, reason} ->
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
else
|
||||
@@ -106,7 +106,7 @@ defmodule AgentCoordinator.VSCodePermissions do
|
||||
# - Trust scores
|
||||
# - Capability declarations
|
||||
# - User-configured permissions
|
||||
|
||||
|
||||
case agent_id do
|
||||
"github_copilot_session" -> :filesystem
|
||||
id when is_binary(id) and byte_size(id) > 0 -> :editor # Other registered agents
|
||||
@@ -150,10 +150,10 @@ defmodule AgentCoordinator.VSCodePermissions do
|
||||
case tool_name do
|
||||
tool when tool in ["vscode_write_file", "vscode_create_file", "vscode_delete_file"] ->
|
||||
check_workspace_bounds(args["path"], context)
|
||||
|
||||
|
||||
"vscode_run_command" ->
|
||||
check_command_safety(args["command"], args["args"])
|
||||
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
@@ -162,44 +162,44 @@ defmodule AgentCoordinator.VSCodePermissions do
|
||||
defp check_workspace_bounds(path, _context) when is_binary(path) do
|
||||
# Ensure file operations are within workspace bounds
|
||||
# This is a simplified check - real implementation would use VS Code workspace API
|
||||
|
||||
|
||||
forbidden_patterns = [
|
||||
# System directories
|
||||
"/etc/", "/bin/", "/usr/", "/var/", "/tmp/",
|
||||
# User sensitive areas
|
||||
# User sensitive areas
|
||||
"/.ssh/", "/.config/", "/home/", "~",
|
||||
# Relative path traversal
|
||||
"../", "..\\"
|
||||
]
|
||||
|
||||
|
||||
if Enum.any?(forbidden_patterns, fn pattern -> String.contains?(path, pattern) end) do
|
||||
{:error, "Path outside workspace bounds or accessing sensitive directories"}
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
defp check_workspace_bounds(_path, _context), do: {:error, "Invalid path format"}
|
||||
|
||||
defp check_command_safety(command, args) when is_binary(command) do
|
||||
cond do
|
||||
command in @whitelisted_commands ->
|
||||
:ok
|
||||
|
||||
|
||||
String.starts_with?(command, "extension.") ->
|
||||
{:error, "Extension commands not allowed for security"}
|
||||
|
||||
|
||||
String.contains?(command, "terminal") ->
|
||||
{:error, "Terminal commands require terminal permission level"}
|
||||
|
||||
|
||||
String.contains?(command, "git") ->
|
||||
{:error, "Git commands require git permission level"}
|
||||
|
||||
|
||||
true ->
|
||||
{:error, "Command '#{command}' not in whitelist"}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
defp check_command_safety(_command, _args), do: {:error, "Invalid command format"}
|
||||
|
||||
@doc """
|
||||
@@ -209,7 +209,7 @@ defmodule AgentCoordinator.VSCodePermissions do
|
||||
%{
|
||||
levels: %{
|
||||
read_only: "File reading, workspace inspection, message display",
|
||||
editor: "Text editing, selections, safe editor commands",
|
||||
editor: "Text editing, selections, safe editor commands",
|
||||
filesystem: "File creation/deletion, directory operations",
|
||||
terminal: "Terminal access and command execution",
|
||||
git: "Version control operations",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
defmodule AgentCoordinator.VSCodeToolProvider do
|
||||
@moduledoc """
|
||||
Provides VS Code Extension API tools as MCP-compatible tools.
|
||||
|
||||
|
||||
This module wraps VS Code's Extension API calls and exposes them as MCP tools
|
||||
that can be used by agents through the unified coordination system.
|
||||
"""
|
||||
@@ -11,9 +11,10 @@ defmodule AgentCoordinator.VSCodeToolProvider do
|
||||
|
||||
@doc """
|
||||
Returns the list of available VS Code tools with their MCP schemas.
|
||||
All tools include agent_id parameter for proper multi-agent identification.
|
||||
"""
|
||||
def get_tools do
|
||||
[
|
||||
base_tools = [
|
||||
# File Operations
|
||||
%{
|
||||
"name" => "vscode_read_file",
|
||||
@@ -26,7 +27,7 @@ defmodule AgentCoordinator.VSCodeToolProvider do
|
||||
"description" => "Relative or absolute path to the file within the workspace"
|
||||
},
|
||||
"encoding" => %{
|
||||
"type" => "string",
|
||||
"type" => "string",
|
||||
"description" => "File encoding (default: utf8)",
|
||||
"enum" => ["utf8", "utf16le", "base64"]
|
||||
}
|
||||
@@ -65,7 +66,7 @@ defmodule AgentCoordinator.VSCodeToolProvider do
|
||||
"name" => "vscode_create_file",
|
||||
"description" => "Create a new file using VS Code's file system API.",
|
||||
"inputSchema" => %{
|
||||
"type" => "object",
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"path" => %{
|
||||
"type" => "string",
|
||||
@@ -91,7 +92,7 @@ defmodule AgentCoordinator.VSCodeToolProvider do
|
||||
"type" => "object",
|
||||
"properties" => %{
|
||||
"path" => %{
|
||||
"type" => "string",
|
||||
"type" => "string",
|
||||
"description" => "Relative or absolute path to the file/directory within the workspace"
|
||||
},
|
||||
"recursive" => %{
|
||||
@@ -117,7 +118,7 @@ defmodule AgentCoordinator.VSCodeToolProvider do
|
||||
"description" => "Relative or absolute path to the directory within the workspace"
|
||||
},
|
||||
"include_hidden" => %{
|
||||
"type" => "boolean",
|
||||
"type" => "boolean",
|
||||
"description" => "Whether to include hidden files/directories (default: false)"
|
||||
}
|
||||
},
|
||||
@@ -203,7 +204,7 @@ defmodule AgentCoordinator.VSCodeToolProvider do
|
||||
"description" => "Start line number (0-based)"
|
||||
},
|
||||
"start_character" => %{
|
||||
"type" => "number",
|
||||
"type" => "number",
|
||||
"description" => "Start character position (0-based)"
|
||||
},
|
||||
"end_line" => %{
|
||||
@@ -269,6 +270,37 @@ defmodule AgentCoordinator.VSCodeToolProvider do
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
# Add agent_id parameter to all tools for multi-agent coordination
|
||||
Enum.map(base_tools, &add_agent_id_parameter/1)
|
||||
end
|
||||
|
||||
# Add agent_id parameter to a tool schema
|
||||
defp add_agent_id_parameter(tool) do
|
||||
input_schema = tool["inputSchema"]
|
||||
properties = Map.get(input_schema, "properties", %{})
|
||||
required = Map.get(input_schema, "required", [])
|
||||
|
||||
# Add agent_id to properties
|
||||
updated_properties = Map.put(properties, "agent_id", %{
|
||||
"type" => "string",
|
||||
"description" => "Unique identifier for the agent making this request. Each agent session must use a consistent, unique ID throughout their interaction. Generate a UUID or use a descriptive identifier like 'agent_main_task_001'."
|
||||
})
|
||||
|
||||
# Add agent_id to required fields
|
||||
updated_required = if "agent_id" in required, do: required, else: ["agent_id" | required]
|
||||
|
||||
# Update the tool schema
|
||||
updated_input_schema = input_schema
|
||||
|> Map.put("properties", updated_properties)
|
||||
|> Map.put("required", updated_required)
|
||||
|
||||
# Update tool description to mention agent_id requirement
|
||||
updated_description = tool["description"] <> " IMPORTANT: Include a unique agent_id parameter to identify your agent session."
|
||||
|
||||
tool
|
||||
|> Map.put("inputSchema", updated_input_schema)
|
||||
|> Map.put("description", updated_description)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -276,29 +308,78 @@ defmodule AgentCoordinator.VSCodeToolProvider do
|
||||
"""
|
||||
def handle_tool_call(tool_name, args, context) do
|
||||
Logger.info("VS Code tool call: #{tool_name} with args: #{inspect(args)}")
|
||||
|
||||
# Check permissions
|
||||
case VSCodePermissions.check_permission(context, tool_name, args) do
|
||||
{:ok, _permission_level} ->
|
||||
# Execute the tool
|
||||
result = execute_tool(tool_name, args, context)
|
||||
|
||||
# Log the operation
|
||||
log_tool_operation(tool_name, args, context, result)
|
||||
|
||||
result
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.warning("Permission denied for #{tool_name}: #{reason}")
|
||||
{:error, %{"error" => "Permission denied", "reason" => reason}}
|
||||
|
||||
# Extract agent_id from args (required for all VS Code tools)
|
||||
agent_id = Map.get(args, "agent_id")
|
||||
|
||||
if is_nil(agent_id) or agent_id == "" do
|
||||
Logger.warning("Missing agent_id in VS Code tool call: #{tool_name}")
|
||||
{:error, %{
|
||||
"error" => "Missing agent_id",
|
||||
"message" => "All VS Code tools require a unique agent_id parameter. Please include your agent session identifier."
|
||||
}}
|
||||
else
|
||||
# Ensure agent is registered and create enhanced context
|
||||
enhanced_context = ensure_agent_registered(agent_id, context)
|
||||
|
||||
# Check permissions with agent-specific context
|
||||
case VSCodePermissions.check_permission(enhanced_context, tool_name, args) do
|
||||
{:ok, _permission_level} ->
|
||||
# Execute the tool
|
||||
result = execute_tool(tool_name, args, enhanced_context)
|
||||
|
||||
# Log the operation
|
||||
log_tool_operation(tool_name, args, enhanced_context, result)
|
||||
|
||||
result
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.warning("Permission denied for #{tool_name} (agent: #{agent_id}): #{reason}")
|
||||
{:error, %{"error" => "Permission denied", "reason" => reason}}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Private function to execute individual tools
|
||||
# Ensure the agent is registered in the system and return enhanced context
|
||||
defp ensure_agent_registered(agent_id, context) do
|
||||
# Check if agent is already registered
|
||||
case AgentCoordinator.TaskRegistry.get_agent(agent_id) do
|
||||
{:ok, _agent} ->
|
||||
# Agent exists, use existing context with agent_id
|
||||
Map.put(context, :agent_id, agent_id)
|
||||
|
||||
{:error, :not_found} ->
|
||||
# Agent not registered, auto-register with VS Code capabilities
|
||||
Logger.info("Auto-registering new agent: #{agent_id}")
|
||||
|
||||
capabilities = [
|
||||
"coding",
|
||||
"analysis",
|
||||
"review",
|
||||
"documentation",
|
||||
"vscode_editing",
|
||||
"vscode_filesystem"
|
||||
]
|
||||
|
||||
case AgentCoordinator.TaskRegistry.register_agent(
|
||||
"GitHub Copilot (#{agent_id})",
|
||||
capabilities,
|
||||
[metadata: %{agent_id: agent_id, auto_registered: true, session_start: DateTime.utc_now()}]
|
||||
) do
|
||||
{:ok, _result} ->
|
||||
Logger.info("Successfully auto-registered agent: #{agent_id}")
|
||||
Map.put(context, :agent_id, agent_id)
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.error("Failed to auto-register agent #{agent_id}: #{inspect(reason)}")
|
||||
Map.put(context, :agent_id, agent_id) # Continue anyway
|
||||
end
|
||||
end
|
||||
end # Private function to execute individual tools
|
||||
defp execute_tool(tool_name, args, context) do
|
||||
case tool_name do
|
||||
"vscode_read_file" -> read_file(args, context)
|
||||
"vscode_write_file" -> write_file(args, context)
|
||||
"vscode_write_file" -> write_file(args, context)
|
||||
"vscode_create_file" -> create_file(args, context)
|
||||
"vscode_delete_file" -> delete_file(args, context)
|
||||
"vscode_list_directory" -> list_directory(args, context)
|
||||
@@ -314,7 +395,7 @@ defmodule AgentCoordinator.VSCodeToolProvider do
|
||||
end
|
||||
|
||||
# Tool implementations (these will call VS Code Extension API via JavaScript bridge)
|
||||
|
||||
|
||||
defp read_file(args, _context) do
|
||||
# For now, return a placeholder - we'll implement the actual VS Code API bridge
|
||||
{:ok, %{
|
||||
|
||||
Reference in New Issue
Block a user