Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/backend/v3/magentic_agents/common/lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from typing import Any

from azure.ai.projects.aio import AIProjectClient
from azure.identity import InteractiveBrowserCredential
from azure.identity.aio import DefaultAzureCredential
from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent
from semantic_kernel.connectors.mcp import MCPStreamableHttpPlugin
Expand Down Expand Up @@ -35,7 +34,7 @@ async def close(self) -> None:
if self._stack is None:
return
try:
self.cred.close()
#self.cred.close()
await self._stack.aclose()
finally:
self._stack = None
Expand Down
3 changes: 3 additions & 0 deletions src/backend/v3/orchestration/human_approval_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ def plan_to_obj(self, magentic_context, ledger) -> MPlan:
line = line.replace('*', '').strip()
break

if not found_agent:
# If no agent found, assign to ProxyAgent if available
found_agent = "MagenticAgent"
# If line indicates a following list of actions (e.g. "Assign **EnhancedResearchAgent**
# to gather authoritative data on:") save and prefix to the steps
if line.endswith(':'):
Expand Down
18 changes: 11 additions & 7 deletions src/mcp_server/mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@
MACAE MCP Server - FastMCP server with organized tools and services.
"""

import argparse
import logging
###
import sys
import argparse
from pathlib import Path
from fastmcp import FastMCP
from fastmcp.server.auth.providers.jwt import JWTVerifier
import logging
from typing import Optional

from config.settings import config
from core.factory import MCPToolFactory
from fastmcp import FastMCP
from fastmcp.server.auth.providers.jwt import JWTVerifier
from services.data_tool_service import DataToolService
from services.general_service import GeneralService
from services.hr_service import HRService
from services.marketing_service import MarketingService
from services.product_service import ProductService
from services.tech_support_service import TechSupportService
from services.general_service import GeneralService
from services.data_tool_service import DataToolService
from config.settings import config

# Setup logging
logging.basicConfig(level=logging.INFO)
Expand All @@ -28,6 +30,8 @@
# Initialize services
factory.register_service(HRService())
factory.register_service(TechSupportService())
factory.register_service(MarketingService())
factory.register_service(ProductService())
factory.register_service(GeneralService())

# Register DataToolService with the dataset path
Expand Down
36 changes: 36 additions & 0 deletions src/mcp_server/services/marketing_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""
Marketing MCP tools service.
"""

from typing import Any, Dict

from core.factory import Domain, MCPToolBase
from utils.date_utils import format_date_for_user
from utils.formatters import format_error_response, format_success_response


class MarketingService(MCPToolBase):
"""Marketing tools for employee onboarding and management."""

def __init__(self):
super().__init__(Domain.HR)

def register_tools(self, mcp) -> None:
"""Register Marketing tools with the MCP server."""

@mcp.tool(tags={self.domain.value})
async def generate_press_release(key_information_for_press_release: str) -> str:
"""This is a function to draft / write a press release. You must call the function by passing the key information that you want to be included in the press release."""

return f"Look through the conversation history. Identify the content. Now you must generate a press release based on this content {key_information_for_press_release}. Make it approximately 2 paragraphs."

@mcp.tool(tags={self.domain.value})
async def handle_influencer_collaboration(influencer_name: str, campaign_name: str) -> str:
"""Handle collaboration with an influencer."""

return f"Collaboration with influencer '{influencer_name}' for campaign '{campaign_name}' handled."

@property
def tool_count(self) -> int:
"""Return the number of tools provided by this service."""
return 2
59 changes: 59 additions & 0 deletions src/mcp_server/services/product_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
Product MCP tools service.
"""

from typing import Any, Dict

from core.factory import Domain, MCPToolBase
from utils.date_utils import format_date_for_user
from utils.formatters import format_error_response, format_success_response


class ProductService(MCPToolBase):
"""Product tools for employee onboarding and management."""

def __init__(self):
super().__init__(Domain.HR)

def register_tools(self, mcp) -> None:
"""Register Product tools with the MCP server."""

@mcp.tool(tags={self.domain.value})
async def get_product_info() -> str:
"""Get information about the different products and phone plans available, including roaming services."""
product_info = """

# Simulated Phone Plans

## Plan A: Basic Saver
- **Monthly Cost**: $25
- **Data**: 5GB
- **Calls**: Unlimited local calls
- **Texts**: Unlimited local texts

## Plan B: Standard Plus
- **Monthly Cost**: $45
- **Data**: 15GB
- **Calls**: Unlimited local and national calls
- **Texts**: Unlimited local and national texts

## Plan C: Premium Unlimited
- **Monthly Cost**: $70
- **Data**: Unlimited
- **Calls**: Unlimited local, national, and international calls
- **Texts**: Unlimited local, national, and international texts

# Roaming Extras Add-On Pack
- **Cost**: $15/month
- **Data**: 1GB
- **Calls**: 200 minutes
- **Texts**: 200 texts

"""
return f"Here is information to relay back to the user. Repeat back all the relevant sections that the user asked for: {product_info}."


@property
def tool_count(self) -> int:
"""Return the number of tools provided by this service."""
return 1
6 changes: 3 additions & 3 deletions src/tests/agents/test_foundry_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,13 @@ async def test_mcp_functionality(self):
if not agent.mcp or not agent.mcp.url:
pytest.skip("MCP configuration not available - skipping MCP test")

query = "Please greet Tom using an MCP tool"
query = "Please greet Tom"

response = await self._get_agent_response(agent, query)

# Check for the expected MCP response indicator
assert "Hello from MCP, Tom" in response, \
f"Expected 'Hello from MCP, Tom' in MCP response, got: {response}"
assert "Hello from MACAE MCP Server, Tom" in response, \
f"Expected 'Hello from MACAE MCP Server, Tom' in MCP response, got: {response}"

except Exception as e:
pytest.fail(f"MCP test failed with error: {e}")
Expand Down
38 changes: 0 additions & 38 deletions src/tests/agents/test_proxy_agent.py
Original file line number Diff line number Diff line change
@@ -1,38 +0,0 @@
"""
Integration tests for FoundryAgentTemplate functionality.
Tests Bing search, RAG, MCP tools, and Code Interpreter capabilities.
"""
# pylint: disable=E0401, E0611, C0413

import asyncio
import os
import sys
import time
from pathlib import Path

import pytest

# Add the backend path to sys.path so we can import v3 modules
backend_path = Path(__file__).parent.parent.parent / "backend"
sys.path.insert(0, str(backend_path))

# Now import from the v3 package
from v3.magentic_agents.proxy_agent import (DummyAgentThread, ProxyAgent,
ProxyAgentResponseItem)


@pytest.mark.asyncio
async def test_proxy_agent(monkeypatch):
"""Test the proxy agent."""
# Mock the input function to simulate user input
monkeypatch.setattr("builtins.input", lambda _: "Jane Doe")

agent = ProxyAgent()
test_messages = [
"More information needed. What is the name of the employee?"
]

for message in test_messages:
async for response in agent.invoke(message):
assert "Human clarification: Jane Doe" in response.message.content, \
f"Unexpected response: {response.message.content}"
Loading