From 14c7127286e1e8508615942e11139b2386e87a45 Mon Sep 17 00:00:00 2001 From: Deeksha Vaidyanathan Date: Mon, 26 Jan 2026 21:03:33 -0800 Subject: [PATCH 1/2] Adding LangChain/Composio integrations with HubSpot, Slack, and Notion --- examples/langchain-composio-notion.py | 85 +++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 examples/langchain-composio-notion.py diff --git a/examples/langchain-composio-notion.py b/examples/langchain-composio-notion.py new file mode 100644 index 0000000..d6b2434 --- /dev/null +++ b/examples/langchain-composio-notion.py @@ -0,0 +1,85 @@ +# Before running, set local environment variables using the export function in the terminal and setting COMPOSIO_API_KEY, COMPOSIO_USER_ID, and ANTHROPIC_API_KEY to their respect tokens for authorization + +import os +import asyncio +from dotenv import load_dotenv + +from composio import Composio +from langchain_mcp_adapters.client import MultiServerMCPClient +from langchain.agents import create_agent +from langchain_anthropic import ChatAnthropic + +load_dotenv() + +async def main(): + # --- Validate environment variables --- + if not os.getenv("COMPOSIO_API_KEY"): + raise ValueError("COMPOSIO_API_KEY is not set") + if not os.getenv("COMPOSIO_USER_ID"): + raise ValueError("COMPOSIO_USER_ID is not set") + if not os.getenv("ANTHROPIC_API_KEY"): + raise ValueError("ANTHROPIC_API_KEY is not set") + + # --- 1. Initialize Composio client --- + composio = Composio(api_key=os.getenv("COMPOSIO_API_KEY")) + + # --- 2. Create Tool Router session for Notion --- + session = composio.create( + user_id=os.getenv("COMPOSIO_USER_ID"), + toolkits=["notion"], + ) + + mcp_url = session.mcp.url + + # --- 3. MCP client (Notion tools) --- + client = MultiServerMCPClient( + { + "notion": { + "transport": "streamable_http", + "url": mcp_url, + "headers": { + "x-api-key": os.getenv("COMPOSIO_API_KEY") + }, + } + } + ) + + tools = await client.get_tools() + + # --- 4. Claude LLM --- + llm = ChatAnthropic( + model="claude-sonnet-4-5-20250929", + temperature=0, + max_tokens=2048, + ) + + # --- 5. LangChain agent --- + agent = create_agent( + model=llm, + tools=tools, + system_prompt=( + "You are a Notion assistant. " + "Use the available tools to read Notion pages and return accurate data. " + "Do not invent content." + ), + ) + + # --- 6. Interactive loop --- + messages = [] + + print("Claude-powered Notion agent ready. Type 'exit' to quit.\n") + + while True: + user_input = input("You: ").strip() + if user_input.lower() in {"exit", "quit"}: + break + + messages.append({"role": "user", "content": user_input}) + + response = await agent.ainvoke({"messages": messages}) + messages = response["messages"] + + print(f"\nAgent: {messages[-1].content}\n") + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file From 925489ccc0b96907c62eea0e877798574f547c2e Mon Sep 17 00:00:00 2001 From: Deeksha Vaidyanathan Date: Mon, 26 Jan 2026 21:04:49 -0800 Subject: [PATCH 2/2] Adding LangChain/Composio integrations with HubSpot and Slack --- examples/langchain-composio-hubspot.py | 87 +++++++++++++++++++++++++ examples/langchain-composio-slack.py | 88 ++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 examples/langchain-composio-hubspot.py create mode 100644 examples/langchain-composio-slack.py diff --git a/examples/langchain-composio-hubspot.py b/examples/langchain-composio-hubspot.py new file mode 100644 index 0000000..088cc9c --- /dev/null +++ b/examples/langchain-composio-hubspot.py @@ -0,0 +1,87 @@ +# Before running, set local environment variables using the export function in the terminal and setting COMPOSIO_API_KEY, COMPOSIO_USER_ID, and ANTHROPIC_API_KEY to their respect tokens for authorization + +import os +import asyncio +from dotenv import load_dotenv + +from composio import Composio +from langchain_mcp_adapters.client import MultiServerMCPClient +from langchain.agents import create_agent +from langchain_anthropic import ChatAnthropic + +load_dotenv() + +async def main(): + # --- Validate environment variables --- + if not os.getenv("COMPOSIO_API_KEY"): + raise ValueError("COMPOSIO_API_KEY is not set") + if not os.getenv("COMPOSIO_USER_ID"): + raise ValueError("COMPOSIO_USER_ID is not set") + if not os.getenv("ANTHROPIC_API_KEY"): + raise ValueError("ANTHROPIC_API_KEY is not set") + + # --- 1. Initialize Composio client --- + composio = Composio(api_key=os.getenv("COMPOSIO_API_KEY")) + + # --- 2. Create Tool Router session for Notion --- + session = composio.create( + user_id=os.getenv("COMPOSIO_USER_ID"), + toolkits=["hubspot"], + ) + + mcp_url = session.mcp.url + + # --- 3. MCP client (Notion tools) --- + client = MultiServerMCPClient( + { + "hubspot": { + "transport": "streamable_http", + "url": mcp_url, + "headers": { + "x-api-key": os.getenv("COMPOSIO_API_KEY") + }, + } + } + ) + + tools = await client.get_tools() + + # --- 4. Claude LLM --- + llm = ChatAnthropic( + model="claude-sonnet-4-5-20250929", + temperature=0, + max_tokens=2048, + ) + + # --- 5. LangChain agent --- + agent = create_agent( + model=llm, + tools=tools, + system_prompt=( + "You are a HubSpot assistant with read-only access." + "Use the available tools to retrieve HubSpot contacts and their properties." + "Do not create, update, or delete any HubSpot data." + "If a request requires modifying data, explain that you are limited to read-only access." + "Return accurate information and do not invent contact details." + ), + ) + + # --- 6. Interactive loop --- + messages = [] + + print("Claude-powered Notion agent ready. Type 'exit' to quit.\n") + + while True: + user_input = input("You: ").strip() + if user_input.lower() in {"exit", "quit"}: + break + + messages.append({"role": "user", "content": user_input}) + + response = await agent.ainvoke({"messages": messages}) + messages = response["messages"] + + print(f"\nAgent: {messages[-1].content}\n") + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/examples/langchain-composio-slack.py b/examples/langchain-composio-slack.py new file mode 100644 index 0000000..b491a0f --- /dev/null +++ b/examples/langchain-composio-slack.py @@ -0,0 +1,88 @@ +# Before running, set local environment variables using the export function in the terminal +# and setting COMPOSIO_API_KEY, COMPOSIO_USER_ID, and ANTHROPIC_API_KEY + +import os +import asyncio +from dotenv import load_dotenv + +from composio import Composio +from langchain_mcp_adapters.client import MultiServerMCPClient +from langchain.agents import create_agent +from langchain_anthropic import ChatAnthropic + +load_dotenv() + +async def main(): + # --- Validate environment variables --- + if not os.getenv("COMPOSIO_API_KEY"): + raise ValueError("COMPOSIO_API_KEY is not set") + if not os.getenv("COMPOSIO_USER_ID"): + raise ValueError("COMPOSIO_USER_ID is not set") + if not os.getenv("ANTHROPIC_API_KEY"): + raise ValueError("ANTHROPIC_API_KEY is not set") + + # --- 1. Initialize Composio client --- + composio = Composio(api_key=os.getenv("COMPOSIO_API_KEY")) + + # --- 2. Create Tool Router session for Slack --- + session = composio.create( + user_id=os.getenv("COMPOSIO_USER_ID"), + toolkits=["slack"], + ) + + mcp_url = session.mcp.url + + # --- 3. MCP client (Slack tools) --- + client = MultiServerMCPClient( + { + "slack": { + "transport": "streamable_http", + "url": mcp_url, + "headers": { + "x-api-key": os.getenv("COMPOSIO_API_KEY") + }, + } + } + ) + + tools = await client.get_tools() + + # --- 4. Claude LLM --- + llm = ChatAnthropic( + model="claude-sonnet-4-5-20250929", + temperature=0, + max_tokens=2048, + ) + + # --- 5. LangChain agent --- + agent = create_agent( + model=llm, + tools=tools, + system_prompt=( + "You are a Slack assistant. " + "Use the available tools to read Slack channels and threads. " + "Summarize conversations clearly, including decisions and action items. " + "Post summaries back to Slack when asked. " + "Do not invent messages." + ), + ) + + # --- 6. Interactive loop --- + messages = [] + + print("Claude-powered Slack agent ready. Type 'exit' to quit.\n") + + while True: + user_input = input("You: ").strip() + if user_input.lower() in {"exit", "quit"}: + break + + messages.append({"role": "user", "content": user_input}) + + response = await agent.ainvoke({"messages": messages}) + messages = response["messages"] + + print(f"\nAgent: {messages[-1].content}\n") + +if __name__ == "__main__": + asyncio.run(main())