gperdrizet commited on
Commit
2daac14
·
unverified ·
2 Parent(s): bc0a05b a28b1b4

Merge pull request #2 from gperdrizet/dev

Browse files
Files changed (3) hide show
  1. README.md +1 -1
  2. client/interface.py +62 -0
  3. rss_client.py +26 -72
README.md CHANGED
@@ -13,4 +13,4 @@ tags:
13
 
14
  [![HuggingFace Space](https://github.com/gperdrizet/rss-mcp-client/actions/workflows/publish_hf_space.yml/badge.svg)](https://github.com/gperdrizet/rss-mcp-client/actions/workflows/publish_hf_space.yml)
15
 
16
- LLM agent RSS feed reader using Model Context Protocol.
 
13
 
14
  [![HuggingFace Space](https://github.com/gperdrizet/rss-mcp-client/actions/workflows/publish_hf_space.yml/badge.svg)](https://github.com/gperdrizet/rss-mcp-client/actions/workflows/publish_hf_space.yml)
15
 
16
+ LLM agent RSS feed reader using Model Context Protocol: try it on [HuggingFace Spaces](https://huggingface.co/spaces/Agents-MCP-Hackathon/rss-mcp-client)
client/interface.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''Functions for controlling chat flow between Gradio and Anthropic/MCP'''
2
+
3
+ import json
4
+ import logging
5
+ from gradio.components.chatbot import ChatMessage
6
+ from client.anthropic_bridge import AnthropicBridge
7
+
8
+ async def agent_input(bridge: AnthropicBridge, chat_history: list) -> list:
9
+ '''Handles model interactions.'''
10
+
11
+ function_logger = logging.getLogger(__name__ + '.agent_input')
12
+
13
+ input_messages = format_chat_history(chat_history)
14
+ result = await bridge.process_query(input_messages)
15
+ function_logger.info(result)
16
+
17
+ try:
18
+ chat_history.append({
19
+ "role": "assistant",
20
+ "content": result['llm_response'].content[0].text
21
+ })
22
+
23
+ except AttributeError:
24
+ function_logger.info('Model called the tool, but did not talk about it')
25
+
26
+ if result['tool_result']:
27
+ articles = json.loads(result['tool_result'].content)['text']
28
+ function_logger.info(articles)
29
+ tmp_chat_history = chat_history.copy()
30
+ tmp_chat_history.append({
31
+ "role": "assistant",
32
+ "content": ('Here are the three most recent entries from the RSS ' +
33
+ f'feed in JSON format. Tell the user what you have found: {json.dumps(articles)}')
34
+ })
35
+
36
+ tmp_input_messages = format_chat_history(tmp_chat_history)
37
+ function_logger.info(tmp_input_messages)
38
+ result = await bridge.process_query(tmp_input_messages)
39
+
40
+ chat_history.append({
41
+ "role": "assistant",
42
+ "content": result['llm_response'].content[0].text
43
+ })
44
+
45
+ return chat_history
46
+
47
+
48
+ def format_chat_history(history) -> list[dict]:
49
+ '''Formats gradio chat history for submission to anthropic.'''
50
+
51
+ messages = []
52
+
53
+ for chat_message in history:
54
+ if isinstance(chat_message, ChatMessage):
55
+ role, content = chat_message.role, chat_message.content
56
+ else:
57
+ role, content = chat_message.get("role"), chat_message.get("content")
58
+
59
+ if role in ["user", "assistant", "system"]:
60
+ messages.append({"role": role, "content": content})
61
+
62
+ return messages
rss_client.py CHANGED
@@ -1,13 +1,12 @@
1
  '''RSS MCP server demonstration client app.'''
2
 
3
  import os
4
- import json
5
  import logging
6
  from pathlib import Path
7
  from logging.handlers import RotatingFileHandler
8
 
9
  import gradio as gr
10
- from gradio.components.chatbot import ChatMessage
11
  from client.mcp_client import MCPClientWrapper
12
  from client.anthropic_bridge import AnthropicBridge
13
 
@@ -30,100 +29,55 @@ logging.basicConfig(
30
 
31
  logger = logging.getLogger(__name__)
32
 
33
- client = MCPClientWrapper('https://agents-mcp-hackathon-rss-mcp-server.hf.space/gradio_api/mcp/sse')
34
- bridge = AnthropicBridge(
35
- client,
 
 
 
36
  api_key=os.environ['ANTHROPIC_API_KEY']
37
  )
38
 
39
- async def submit_input(message: str, chat_history: list) -> str:
40
  '''Submits user message to agent'''
41
 
42
  function_logger = logging.getLogger(__name__ + '.submit_input')
 
43
 
44
  chat_history.append({"role": "user", "content": message})
45
- input_messages = format_chat_history(chat_history)
46
- function_logger.info(input_messages)
47
-
48
- result = await bridge.process_query(input_messages)
49
- function_logger.info(result)
50
- function_logger.info(result.keys())
51
-
52
- try:
53
- chat_history.append({
54
- "role": "assistant",
55
- "content": result['llm_response'].content[0].text
56
- })
57
-
58
- except AttributeError:
59
- function_logger.info('Model called the tool, but did not talk about it')
60
-
61
- if result['tool_result']:
62
- articles = json.loads(result['tool_result'].content)['text']
63
- function_logger.info(articles)
64
- tmp_chat_history = chat_history.copy()
65
- tmp_chat_history.append({
66
- "role": "assistant",
67
- "content": ('Here are the three most recent entries from the RSS ' +
68
- f'feed in JSON format. Tell the user what you have found: {json.dumps(articles)}')
69
- })
70
-
71
- tmp_input_messages = format_chat_history(tmp_chat_history)
72
- function_logger.info(tmp_input_messages)
73
- result = await bridge.process_query(tmp_input_messages)
74
-
75
- chat_history.append({
76
- "role": "assistant",
77
- "content": result['llm_response'].content[0].text
78
- })
79
-
80
 
81
  return '', chat_history
82
 
83
 
84
- def format_chat_history(history) -> list[dict]:
85
- '''Formats gradio chat history for submission to anthropic.'''
86
-
87
- messages = []
88
-
89
- for chat_message in history:
90
- if isinstance(msg, ChatMessage):
91
- role, content = chat_message.role, chat_message.content
92
- else:
93
- role, content = chat_message.get("role"), chat_message.get("content")
94
-
95
- if role in ["user", "assistant", "system"]:
96
- messages.append({"role": role, "content": content})
97
-
98
- return messages
99
-
100
-
101
  with gr.Blocks(title='MCP RSS client') as demo:
102
- gr.Markdown('# MCP RSS reader')
103
- gr.Markdown(
104
- 'Connect to the MCP RSS server: ' +
105
- 'https://huggingface.co/spaces/Agents-MCP-Hackathon/rss-mcp-server'
106
- )
107
-
108
- connect_btn = gr.Button('Connect')
109
- status = gr.Textbox(label='Connection Status', interactive=False, lines=10)
 
 
 
110
 
111
  chatbot = gr.Chatbot(
112
  value=[],
113
  height=500,
114
  type='messages',
115
- show_copy_button=True,
116
- avatar_images=('👤', '🤖')
117
  )
118
 
119
  msg = gr.Textbox(
120
- label='Your Question',
121
- placeholder='Ask about an RSS feed',
122
  scale=4
123
  )
124
 
125
- connect_btn.click(client.list_tools, outputs=status) # pylint: disable=no-member
126
- msg.submit(submit_input, [msg, chatbot], [msg, chatbot]) # pylint: disable=no-member
127
 
128
  if __name__ == '__main__':
129
 
 
1
  '''RSS MCP server demonstration client app.'''
2
 
3
  import os
 
4
  import logging
5
  from pathlib import Path
6
  from logging.handlers import RotatingFileHandler
7
 
8
  import gradio as gr
9
+ import client.interface as interface
10
  from client.mcp_client import MCPClientWrapper
11
  from client.anthropic_bridge import AnthropicBridge
12
 
 
29
 
30
  logger = logging.getLogger(__name__)
31
 
32
+ RSS_CLIENT = MCPClientWrapper(
33
+ 'https://agents-mcp-hackathon-rss-mcp-server.hf.space/gradio_api/mcp/sse'
34
+ )
35
+
36
+ BRIDGE = AnthropicBridge(
37
+ RSS_CLIENT,
38
  api_key=os.environ['ANTHROPIC_API_KEY']
39
  )
40
 
41
+ async def send_message(message: str, chat_history: list) -> str:
42
  '''Submits user message to agent'''
43
 
44
  function_logger = logging.getLogger(__name__ + '.submit_input')
45
+ function_logger.info('Submitting user message: %s', message)
46
 
47
  chat_history.append({"role": "user", "content": message})
48
+ chat_history = await interface.agent_input(BRIDGE, chat_history)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
  return '', chat_history
51
 
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  with gr.Blocks(title='MCP RSS client') as demo:
54
+ gr.Markdown('# Agentic RSS reader')
55
+ gr.Markdown("""
56
+ Uses sister Space
57
+ [RSS feed reader](https://huggingface.co/spaces/Agents-MCP-Hackathon/rss-mcp-server)
58
+ via MCP. Click 'Connect to MCP server' to get started. Check out the
59
+ [main project repo on GitHub](https://github.com/gperdrizet/MCP-hackathon/tree/main).
60
+ Both Spaces by [George Perdrizet](https://www.linkedin.com/in/gperdrizet/).
61
+ """)
62
+
63
+ connect_btn = gr.Button('Connect to MCP server')
64
+ status = gr.Textbox(label='MCP server tool dump', interactive=False, lines=4)
65
 
66
  chatbot = gr.Chatbot(
67
  value=[],
68
  height=500,
69
  type='messages',
70
+ show_copy_button=True
 
71
  )
72
 
73
  msg = gr.Textbox(
74
+ label='Ask about content or articles on a site or platform',
75
+ placeholder='Is there anything new on Hacker News?',
76
  scale=4
77
  )
78
 
79
+ connect_btn.click(RSS_CLIENT.list_tools, outputs=status) # pylint: disable=no-member
80
+ msg.submit(send_message, [msg, chatbot], [msg, chatbot]) # pylint: disable=no-member
81
 
82
  if __name__ == '__main__':
83