Skip to content

Commit 258d9d4

Browse files
committed
Add the first implementation
1 parent dc13dcf commit 258d9d4

File tree

7 files changed

+404
-0
lines changed

7 files changed

+404
-0
lines changed

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Python-generated files
2+
__pycache__/
3+
*.py[oc]
4+
build/
5+
dist/
6+
wheels/
7+
*.egg-info
8+
9+
# Virtual environments
10+
.venv

.python-version

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

pyproject.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[project]
2+
name = "mcp-server-calculator"
3+
version = "0.1.0"
4+
description = "A Model Context Protocol server for calculating"
5+
readme = "README.md"
6+
requires-python = ">=3.10"
7+
authors = [{ name = "He Jie", email = "[email protected]" }]
8+
keywords = ["mcp", "llm", "math", "calculator"]
9+
license = { text = "MIT" }
10+
classifiers = [
11+
"Development Status :: 4 - Beta",
12+
"Intended Audience :: Developers",
13+
"License :: OSI Approved :: MIT License",
14+
"Programming Language :: Python :: 3",
15+
"Programming Language :: Python :: 3.10",
16+
]
17+
dependencies = [
18+
"mcp>=1.4.1",
19+
]
20+
21+
[project.scripts]
22+
mcp-server-calculator = "mcp_server_calculator:main"
23+
24+
[build-system]
25+
requires = ["hatchling"]
26+
build-backend = "hatchling.build"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .calculator import main
2+
3+
if __name__ == "__main__":
4+
main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from mcp_server_calculator import main
2+
3+
main()
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import ast
2+
import operator
3+
from mcp.server.fastmcp import FastMCP
4+
5+
def evaluate(expression: str) -> str:
6+
allowed_operators = {
7+
ast.Add: operator.add,
8+
ast.Sub: operator.sub,
9+
ast.Mult: operator.mul,
10+
ast.Div: operator.truediv,
11+
ast.FloorDiv: operator.floordiv,
12+
ast.Mod: operator.mod,
13+
ast.Pow: operator.pow,
14+
ast.USub: operator.neg,
15+
}
16+
17+
def eval_expr(node):
18+
if isinstance(node, ast.Constant):
19+
return node.value
20+
elif isinstance(node, ast.BinOp):
21+
left = eval_expr(node.left)
22+
right = eval_expr(node.right)
23+
if type(node.op) in allowed_operators:
24+
return allowed_operators[type(node.op)](left, right)
25+
elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.USub):
26+
return -eval_expr(node.operand)
27+
raise ValueError("Unsupported operation")
28+
29+
parsed_expr = ast.parse(expression, mode='eval')
30+
result = eval_expr(parsed_expr.body)
31+
return str(result)
32+
33+
mcp = FastMCP("calculator")
34+
35+
@mcp.tool()
36+
async def calculate(expression: str) -> str:
37+
"""Calculates/evaluates the given expression."""
38+
return evaluate(expression)
39+
40+
def main():
41+
mcp.run()

uv.lock

Lines changed: 319 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)