Skip to content

Commit 2c277c9

Browse files
Merge pull request #23 from insightbuilder/mcp-excel-server
Implementation of mcp excel server
2 parents b67c7fe + 292b132 commit 2c277c9

9 files changed

Lines changed: 1053 additions & 0 deletions

File tree

docs/mcp_excel_server.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# MCP Server to Analyze and Work with Excel files
2+
3+
Excel file analysis and automation is a major task
4+
done by the knowledge workers across the
5+
organisations. The data is transferred between the
6+
users, services and their managers in form of
7+
table.
8+
9+
MCP servers have the tools, and resources that can
10+
be made to work with excel sheets and extract
11+
analysis from it.
12+
13+
We are implementing the MCP Server not just to
14+
analyse the excel file. The tools in the server
15+
can manipulate the excel files and the data in the
16+
cells. The mcp implementation will use uv package
17+
management tool. You can find more info about it
18+
in this [video](https://youtu.be/0Lz_oXjqicE)
19+
20+
## Project Details:
21+
22+
- Project Path: ../mcp_excel_server/
23+
24+
The above project folder alone can be downloaded
25+
using
26+
[github-download-directory](https://download-directory.github.io/)
27+
28+
### Project setup commands:
29+
30+
The tool is executed in the terminal or command
31+
prompt. If you have never used the terminal, the
32+
video explaining the process will be available in
33+
the below playlist.
34+
35+
```bash
36+
# install uv tool, which is the python package manager
37+
curl -LsSf https://astral.sh/uv/install.sh | sh
38+
39+
cd mcp_excel_server
40+
# pyproject.toml will contain the libraries that are used in the project
41+
42+
uv run mcpclient.py server.py
43+
44+
After the client start, you will be prompted for the query.
45+
46+
Query: Who are you?.
47+
```
48+
49+
### Available MCP Server Tools:
50+
51+
These tool are using mcp resources that are
52+
manipulating and analysing the excel files.
53+
54+
- xlsx_to_html_table : Used for analysing the data
55+
- create_excel_file : Create excel file
56+
- read_excel_file_cell : Reads the excel file
57+
designated cell
58+
- write_to_excel_file_cell: Writes data to a
59+
designated cell
60+
- write_formula_to_excel_file_cell: Writes formula
61+
to a designated cell
62+
- delete_value_at_cell: Deletes data from a
63+
designated cell
64+
- search_excel_sheet_for_value: Searches for a
65+
value in given excel file
66+
- write_analysis_md: Write data to the markdown
67+
file
68+
- remove_file: Removes a file from the system
69+
70+
When you need use mcp inspector to debug the code,
71+
use the command below. Ensure you have
72+
[npx](https://docs.npmjs.com/cli/v8/commands/npx)
73+
and [node](https://nodejs.org/en/download)
74+
installed
75+
76+
npx @modelcontextprotocol/inspector uv run
77+
server.py
78+
79+
### Project References
80+
81+
- Server code referred from :
82+
[MCP Installation](https://github.com/modelcontextprotocol/python-sdk?tab=readme-ov-file#installation)
83+
84+
- Client code referred from:
85+
[Introducing Clients](https://modelcontextprotocol.io/quickstart/client)
86+
87+
- Notion Code referred from:
88+
[Notion Example code](../fw_ex/notionapi_spike/)
89+
90+
```
91+
92+
```

mcp_excel_server/.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.11

mcp_excel_server/README.md

Whitespace-only changes.
7.78 KB
Binary file not shown.

mcp_excel_server/mcpclient.py

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import asyncio
2+
from typing import Optional
3+
from contextlib import AsyncExitStack
4+
5+
# pyright: reportMissingImports=false
6+
# pyright: reportOptionalSubscript=false
7+
8+
from mcp import ClientSession, StdioServerParameters
9+
from mcp.client.stdio import stdio_client
10+
11+
from anthropic import Anthropic
12+
from dotenv import load_dotenv
13+
14+
# uncomment this when running in your local environment
15+
# ensure you have updated the .env file with the Anthropic API Key
16+
# load_dotenv() # load environment variables from .env
17+
18+
19+
class MCPClient:
20+
def __init__(self):
21+
# Initialize session and client objects
22+
self.session: Optional[ClientSession] = None
23+
self.exit_stack = AsyncExitStack()
24+
self.anthropic = Anthropic()
25+
26+
# methods will go here
27+
async def connect_to_server(self, server_script_path: str):
28+
"""Connect to notion MCP server
29+
30+
Args:
31+
server_script_path: Path to the server script (.py or .js)
32+
"""
33+
is_python = server_script_path.endswith(".py")
34+
is_js = server_script_path.endswith(".js")
35+
if not (is_python or is_js):
36+
raise ValueError("Server script must be a .py or .js file")
37+
38+
command = "python" if is_python else "node"
39+
server_params = StdioServerParameters(
40+
command=command, args=[server_script_path], env=None
41+
)
42+
43+
stdio_transport = await self.exit_stack.enter_async_context(
44+
stdio_client(server_params)
45+
)
46+
self.stdio, self.write = stdio_transport
47+
self.session = await self.exit_stack.enter_async_context(
48+
ClientSession(self.stdio, self.write)
49+
)
50+
51+
await self.session.initialize()
52+
53+
# List available tools
54+
response = await self.session.list_tools()
55+
tools = response.tools
56+
print(
57+
"\nConnected to Excel Analysis MCP server with tools:",
58+
[tool.name for tool in tools],
59+
)
60+
61+
async def process_query(self, query: str) -> str:
62+
"""Process a query using Claude and available tools"""
63+
64+
hal_system = """You are hal3025, an expert in working on filesystem and excel sheets.
65+
You have access to a local filesystem with read and write access.
66+
You are very good in analysing xlsx files and you can use the available
67+
tools with you and return the results to the user.
68+
Just use the tools, and provide the updates the tools are giving.
69+
Do not use external python packages for the analysis.
70+
Use the tools that are available to you.
71+
Do not apologize. Do not provide guidance or examples. Do not share what you cannot do.
72+
Please do not provide the python code for the user requests.
73+
Do not explain how something can be done."""
74+
75+
messages = [{"role": "user", "content": query}]
76+
77+
response = await self.session.list_tools()
78+
available_tools = [
79+
{
80+
"name": tool.name,
81+
"description": tool.description,
82+
"input_schema": tool.inputSchema,
83+
}
84+
for tool in response.tools
85+
]
86+
87+
# Initial Claude API call
88+
response = self.anthropic.messages.create(
89+
model="claude-3-5-haiku-20241022",
90+
max_tokens=1000,
91+
system=hal_system,
92+
messages=messages,
93+
tools=available_tools,
94+
)
95+
96+
# Process response and handle tool calls
97+
tool_results = []
98+
final_text = []
99+
100+
for content in response.content:
101+
if content.type == "text":
102+
final_text.append(content.text)
103+
elif content.type == "tool_use":
104+
tool_name = content.name
105+
tool_args = content.input
106+
107+
# Execute tool call
108+
result = await self.session.call_tool(tool_name, tool_args)
109+
tool_results.append({"call": tool_name, "result": result})
110+
final_text.append(f"[Calling tool {tool_name} with args {tool_args}]")
111+
112+
# Continue conversation with tool results
113+
if hasattr(content, "text") and content.text:
114+
messages.append({"role": "assistant", "content": content.text})
115+
messages.append({"role": "user", "content": result.content})
116+
117+
# Get next response from Claude
118+
response = self.anthropic.messages.create(
119+
model="claude-3-5-haiku-20241022",
120+
system=hal_system,
121+
max_tokens=1000,
122+
messages=messages,
123+
)
124+
125+
final_text.append(response.content[0].text)
126+
127+
return "\n".join(final_text)
128+
129+
async def chat_loop(self):
130+
"""Run an interactive chat loop"""
131+
print("\nMCP Client Started!")
132+
print("Type your queries or 'quit' to exit.")
133+
134+
while True:
135+
try:
136+
query = input("\nInteract with Excel File here: ").strip()
137+
138+
if query.lower() == "quit":
139+
break
140+
141+
response = await self.process_query(query)
142+
print("\n" + response)
143+
144+
except Exception as e:
145+
print(f"\nError: {str(e)}")
146+
147+
async def cleanup(self):
148+
"""Clean up resources"""
149+
await self.exit_stack.aclose()
150+
151+
152+
async def main():
153+
if len(sys.argv) < 2:
154+
print("Usage: python mcpclient.py mcpserver.py")
155+
sys.exit(1)
156+
157+
client = MCPClient()
158+
try:
159+
await client.connect_to_server(sys.argv[1])
160+
await client.chat_loop()
161+
finally:
162+
await client.cleanup()
163+
164+
165+
if __name__ == "__main__":
166+
import sys
167+
168+
asyncio.run(main())

mcp_excel_server/pyproject.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[project]
2+
name = "mcp-excel-server"
3+
version = "0.1.0"
4+
description = "Add your description here"
5+
readme = "README.md"
6+
requires-python = ">=3.11"
7+
dependencies = [
8+
"anthropic>=0.50.0",
9+
"mcp[cli]>=1.6.0",
10+
"openpyxl>=3.1.5",
11+
"python-dotenv>=1.1.0",
12+
]

0 commit comments

Comments
 (0)