Multi-Agent System in Practice: Building an Automated Weekly Report Generator with LangChain + MCP

技术架构AI agents in production

Why Weekly Reports Need Multi-Agent?

Weekly reports are every developer's pain point — not because they're hard to write, but because collecting data is tedious:

  • Pull completed tasks from Jira
  • Count code commits from Git
  • Get meeting notes from Slack/Teams
  • Check production alerts from monitoring
  • Finally "polish" it into a format management likes

If one Agent can only do one thing, let multiple Agents collaborate — that's the value of multi-agent systems.


System Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Orchestrator Agent                        │
│                  LangChain AgentExecutor                    │
└──────────┬──────────┬──────────┬──────────┬────────────────┘
           │          │          │          │
     ┌─────▼────┐ ┌───▼────┐ ┌──▼───┐ ┌───▼────┐
     │  Data    │ │  Code  │ │Meeting│ │ Report │
     │ Collector│ │ Analyst│ │Summary│ │Generator│
     └─────┬────┘ └───┬────┘ └──┬───┘ └───┬────┘
           │          │          │          │
     ┌─────▼──────────▼──────────▼──────────▼────────────────┐
     │                  MCP Server Layer                      │
     │  [Jira MCP] [Git MCP] [Slack MCP] [Monitor MCP]       │
     └───────────────────────────────────────────────────────┘

Step 1: Define Agents

1.1 Data Collector Agent

from langchain_openai import ChatOpenAI
from langchain_mcp import MCPToolkit

jira_toolkit = MCPToolkit(url="http://localhost:8081/mcp/sse")
git_toolkit = MCPToolkit(url="http://localhost:8082/mcp/sse")

data_collector_agent = {
    "name": "data_collector",
    "role": "Data Collection Expert",
    "goal": "Collect work data from Jira and Git for this week",
    "tools": jira_toolkit.get_tools() + git_toolkit.get_tools(),
    "llm": ChatOpenAI(model="gpt-4o", temperature=0)
}

1.2 Code Analyst Agent

code_analyst_agent = {
    "name": "code_analyst",
    "role": "Code Analysis Expert",
    "goal": "Analyze code changes this week and extract key insights",
    "tools": git_toolkit.get_tools(),
    "llm": ChatOpenAI(model="gpt-4o", temperature=0)
}

1.3 Meeting Summarizer Agent

slack_toolkit = MCPToolkit(url="http://localhost:8083/mcp/sse")

meeting_summarizer_agent = {
    "name": "meeting_summarizer",
    "role": "Meeting Summary Expert",
    "goal": "Extract key decisions and action items from meeting notes",
    "tools": slack_toolkit.get_tools(),
    "llm": ChatOpenAI(model="gpt-4o", temperature=0)
}

1.4 Report Generator Agent

email_toolkit = MCPToolkit(url="http://localhost:8084/mcp/sse")

report_generator_agent = {
    "name": "report_generator",
    "role": "Report Generation Expert",
    "goal": "Consolidate all data into a well-structured weekly report",
    "tools": email_toolkit.get_tools(),
    "llm": ChatOpenAI(model="gpt-4o", temperature=0.3)
}

Step 2: Implement MCP Servers

2.1 Jira MCP Server

from mcp.server import Server, Tool
from jira import JIRA

server = Server("jira-mcp-server")
jira_client = JIRA(
    server="https://yourcompany.atlassian.net",
    basic_auth=("email", "api_token")
)

@server.tool(name="get_completed_issues", description="Get completed Jira issues in a date range")
async def get_completed_issues(start_date: str, end_date: str, assignee: str = None):
    jql = f'updated >= "{start_date}" AND updated <= "{end_date}" AND status = Done'
    if assignee:
        jql += f' AND assignee = "{assignee}"'

    issues = jira_client.search_issues(jql, maxResults=50)

    results = []
    for issue in issues:
        results.append({
            "key": issue.key,
            "summary": issue.fields.summary,
            "status": issue.fields.status.name,
            "assignee": issue.fields.assignee.displayName if issue.fields.assignee else "Unassigned",
            "priority": issue.fields.priority.name,
            "updated": issue.fields.updated
        })

    return {"issues": results, "total": len(results)}

2.2 Git MCP Server

from git import Repo
from datetime import datetime, timedelta

server = Server("git-mcp-server")

@server.tool(name="get_commit_stats", description="Get Git commit statistics for a time range")
async def get_commit_stats(repo_path: str, author: str = None, days: int = 7):
    repo = Repo(repo_path)
    since = datetime.now() - timedelta(days=days)

    commits = list(repo.iter_commits(since=since))
    if author:
        commits = [c for c in commits if author in c.author.name]

    stats = {
        "total_commits": len(commits),
        "insertions": 0,
        "deletions": 0,
        "daily_breakdown": {}
    }

    for commit in commits:
        stats["insertions"] += commit.stats.total["insertions"]
        stats["deletions"] += commit.stats.total["deletions"]
        day = commit.committed_datetime.strftime("%Y-%m-%d")
        stats["daily_breakdown"][day] = stats["daily_breakdown"].get(day, 0) + 1

    return stats

Step 3: Orchestrate with LangGraph

from langgraph.graph import StateGraph, END
from typing import TypedDict, Dict, Any

class WeeklyReportState(TypedDict):
    user: str
    week_start: str
    week_end: str
    jira_data: Dict[str, Any]
    git_data: Dict[str, Any]
    meeting_data: Dict[str, Any]
    report: str

def collect_jira_data(state):
    result = data_collector_agent.invoke({
        "input": f"Get completed Jira tasks for {state['user']} from {state['week_start']} to {state['week_end']}"
    })
    state["jira_data"] = result
    return state

def collect_git_data(state):
    result = code_analyst_agent.invoke({
        "input": f"Analyze code commits for {state['user']} from {state['week_start']} to {state['week_end']}"
    })
    state["git_data"] = result
    return state

def collect_meeting_data(state):
    result = meeting_summarizer_agent.invoke({
        "input": f"Extract meeting key info from {state['week_start']} to {state['week_end']}"
    })
    state["meeting_data"] = result
    return state

def generate_report(state):
    prompt = f"""Generate a weekly report based on:
    Jira: {state['jira_data']}
    Git: {state['git_data']}
    Meetings: {state['meeting_data']}
    Include: Work summary, Key achievements, Risks, Next week plan"""
    result = report_generator_agent.invoke({"input": prompt})
    state["report"] = result
    return state

workflow = StateGraph(WeeklyReportState)
workflow.add_node("collect_jira", collect_jira_data)
workflow.add_node("collect_git", collect_git_data)
workflow.add_node("collect_meeting", collect_meeting_data)
workflow.add_node("generate_report", generate_report)

workflow.add_edge("collect_jira", "collect_git")
workflow.add_edge("collect_git", "collect_meeting")
workflow.add_edge("collect_meeting", "generate_report")
workflow.add_edge("generate_report", END)
workflow.set_entry_point("collect_jira")

app = workflow.compile()

Step 4: Execute

result = app.invoke({
    "user": "zhangsan",
    "week_start": "2026-06-05",
    "week_end": "2026-06-11",
    "jira_data": {},
    "git_data": {},
    "meeting_data": {},
    "report": ""
})

print(result["report"])

Production Enhancements

Scheduled Execution

from apscheduler.schedulers.asyncio import AsyncIOScheduler

scheduler = AsyncIOScheduler()

@scheduler.scheduled_job('cron', day_of_week='fri', hour=17, minute=0)
async def weekly_report_job():
    users = get_all_team_members()
    for user in users:
        result = await app.ainvoke({
            "user": user,
            "week_start": get_week_start(),
            "week_end": get_week_end(),
        })
        await send_report_email(user, result["report"])

scheduler.start()

Pitfalls

Pitfall 1: MCP Server Connection Timeout

Symptom: Agent calls to MCP Server occasionally timeout
Cause: Jira API is slow (P99 > 5s), MCP default timeout is 3s
Fix: Increase MCP Client timeout

toolkit = MCPToolkit(url="http://localhost:8081/mcp/sse", timeout=30)

Pitfall 2: Agent Hallucination — Fabricating Tasks

Symptom: Report generator sometimes "invents" tasks not in the data
Cause: LLM creativity, temperature too high
Fix: Use temperature=0 for data collection, emphasize "only use provided data" in prompt

Pitfall 3: Concurrent MCP Connection Conflicts

Symptom: Connection errors during parallel collection
Cause: Multiple Agents using the same MCP Client
Fix: Each Agent gets its own MCP Client instance


Summary

Multi-agent systems turn weekly report generation from "manual assembly" to "automated pipeline":

  1. Clear division of labor: Each Agent does one thing well
  2. MCP decoupling: Agents access tools through MCP Servers, easy to swap and test
  3. LangGraph orchestration: Supports serial, parallel, and conditional workflows
  4. Production-ready: Scheduled execution, error retry, hallucination control

Multi-agent isn't "multiple chatbots" — it's "a software system" where each Agent is a microservice and MCP is the API gateway.

Try these browser-local tools — no sign-up required →

#多智能体#LangChain#MCP#自动化周报#Agent协作