Metadata-Version: 2.4
Name: mcp-nequeo
Version: 2.7.28
Summary: Model Context Protocol (MCP) client and server implementation
Author-email: Drazen Zadravec <noreply@dznequeo.net>
Maintainer-email: Drazen Zadravec <noreply@dznequeo.net>
License-Expression: MIT
Project-URL: Homepage, https://github.com/drazenzadravec/tools/tree/master/ai/mcp
Project-URL: Issues, https://github.com/drazenzadravec/tools/issues
Project-URL: Source, https://github.com/drazenzadravec/tools/tree/master/ai/mcp/python
Keywords: mcp,mcp-client,mcp-server,python,client,browser,server,model context protocol,model-context-protocol
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Build Tools
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp
Requires-Dist: pydantic
Dynamic: license-file

# Model Context Protocol (MCP) Client and Server

[![PyPI v2.7.28](https://img.shields.io/badge/pypi-v2.7.28-orange)](https://pypi.org/project/mcp-nequeo/)
[![License MIT](https://img.shields.io/badge/License-MIT-%23d8b800)](https://github.com/drazenzadravec/tools/blob/master/LICENSE)
[![GitHub Repo](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/drazenzadravec/tools/tree/master)
[![Python v3.13](https://img.shields.io/badge/Python-3.13+-blue)](https://www.python.org/downloads/)

Client supports Stdio and Streamable HTTP. Server supports Stdio and Streamable HTTP.

## Install
pip install mcp-nequeo

## Usage
### Client
```python
from ..McpClient import McpClient

class SampleClient(McpClient):
    """
    Sample Client.
    """
    def __init__(self):
        super().__init__()
```

### Server
```python
from ..McpServerBase import McpServerBase
from ..McpTypes import McpPromptHelper

class SampleServer(McpServerBase):
    """
    Sample Server
    """
    def __init__(self):
        super().__init__("SampleServer", "1.0.1", "Sample server", 
                         dict( resources={}, tools={}, prompts={}))
```

### SymPy Client
```python
from typing import Optional, Any, List, Union

from ..McpClient import McpClient

# SymPy Math Expression Evaluator.
class SymPyMath(McpClient):
    """
    SymPy Math Expression Evaluator.
    """
    def __init__(self):
        super().__init__()

    async def callMathExpressionEvaluatorTool(self, expression: str) -> Union[Any, None]:
        """
        call the math expression evaluator tool.

        Args:
            expression: the math expression.

        Return:
            the evaluated expression.
        """
        res: Any = await self.callTool("SymPy_MathExpressionEvaluator", args={"expression": expression})

        # return the result.
        return res

    async def callMathExpressionEvaluatorPrompt(self, expression: str) -> Union[Any, None]:
        """
        call the math expression evaluator prompt.

        Args:
            expression: the math expression.

        Return:
            the evaluated expression.
        """
        res: Any = await self.callPrompt("MathExpressionEvaluator", args={"expression": expression})

        # return the result.
        return res

    async def callMathExpressionResultPrompt(self, result: str) -> Union[Any, None]:
        """
        call the math expression result prompt.

        Args:
            result: the math result.

        Return:
            the evaluated result.
        """
        res: Any = await self.callPrompt("MathExpressionResult", args={"result": result})

        # return the result.
        return res

    async def callSymPyDocsUrlResource(self) -> Union[Any, None]:
        """
        call the SymPy documentation URL resource.

        Return:
            the resource result.
        """
        res: Any = await self.callResource("sympy://{version}")

        # return the result.
        return res

    async def callSymPyDocsUrlVersionResource(self, version: str) -> Union[Any, None]:
        """
        call the SymPy documentation URL resource.

        Args:
            version: the version.

        Return:
            the resource result.
        """
        res: Any = await self.callResource(f"sympy://doc/{version}/num")

        # return the result.
        return res
```

### SymPy Server
```python
from sympy import *
from sympy import sympify

from typing import Optional, Any, List, Union, Callable, Awaitable

from mcp.types import ToolAnnotations
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.prompts.base import PromptArgument, Message, TextContent

from ..McpServerBase import McpServerBase
from ..McpTypes import McpPromptHelper

# SymPy Math Expression Evaluator.
class SymPyMath(McpServerBase):
    """
    SymPy math expression evaluator.
    """
    def __init__(self):
        super().__init__("SymPyMathExpression", "1.2.1", "SymPy math expression evaluator", 
                         dict( resources={}, tools={}, prompts={}))

    def registerTool_MathExpressionEvaluator(self) -> bool:
        """
        register tool math expression evaluator.

        Return:
            true if tool registered; else false.
        """
        result: bool = self.registerTool(
            "SymPy_MathExpressionEvaluator", 
            self.mathExpressionEvaluator,
            "Use SymPy to execute the mathematical expressions")

        # if added
        if (result):
            # set parameters
            self.setToolParameters("SymPy_MathExpressionEvaluator", {
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "the SymPy mathematical expression"
                    }
                },
                "required": ["expression"],
                "additionalProperties": False
            })
        return result

    def registerPrompt_MathExpressionEvaluator(self) -> bool:
        """
        register prompt math expression evaluator.

        Return:
            true if prompt registered; else false.
        """
        return self.registerPrompt(
            "MathExpressionEvaluator",
            self.mathExpressionEvaluatorPrompt,
            "Evaluate the mathematical expression",
            [ PromptArgument(name = "expression", description = "the SymPy mathematical expression", required = True) ]
        )

    def registerPrompt_MathExpressionResult(self) -> bool:
        """
        register prompt math expression result.

        Return:
            true if prompt registered; else false.
        """
        return self.registerPrompt(
            "MathExpressionResult",
            self.mathExpressionResultPrompt,
            "Describe the expression result",
            [ PromptArgument(name = "result", description = "the math evaluated result", required = True) ]
        )

    def registerResource_SymPyDocsUrl(self) -> bool:
        """
        register resource sympy documentation URL.

        Return:
            true if resource registered; else false.
        """
        return self.registerResource(
            "MathExpressionSymPyDocsUrl",
            "sympy://{version}",
            self.mathExpressionSymPyDocsUrlResource,
            "Get the SymPy documentation URL",
            "text/plain"
        )

    def registerResource_SymPyDocsUrl_Version(self) -> bool:
        """
        register resource sympy documentation URL version.

        Return:
            true if resource registered; else false.
        """
        return self.registerResourceTemplate(
            "MathExpressionSymPyDocsUrlVersion",
            "sympy://doc/{version}/num",
            self.mathExpressionSymPyDocsUrlVersionResource,
            "Get the SymPy documentation URL version",
            "text/plain"
        )

    def mathExpressionEvaluatorPrompt(self, expression: str) -> List[Message]:
        """
        prompt math expression evaluator.

        Args:
            expression:    expression to evaluate.

        Return:
            the prompt result.
        """
        return [ 
            Message(
                role = "user", 
                content = TextContent(
                    type = "text", 
                    text = f"evaluate the math expression: {expression}")
            )
        ]

    def mathExpressionResultPrompt(self, result: str) -> List[Message]:
        """
        prompt math expression result.

        Args:
            result:    expression to evaluate.

        Return:
            the prompt result.
        """
        return [ 
            Message(
                role = "user", 
                content = TextContent(
                    type = "text", 
                    text = f"describe the result: {result}, using latex")
            )
        ]

    def mathExpressionEvaluator(self, expression: str) -> str:
        """
        use SymPy to execute the mathematical expressions

        Args:
            expression:    the SymPy mathematical expression.

        Return:
            the expression result.
        """
        result = ""
        
        try:
            expr = sympify(expression)
            result = expr.evalf(15)
        except Exception as e:
            try:
                expr = sympify(expression)
                result = str(expr)
            except Exception as e:
                result = f"error: {e}"

        # return the result.
        return result

    def mathExpressionSymPyDocsUrlResource(self) -> str:
        """
        SymPy documentation URL resource.

        Return:
            the resource result.
        """
        return f"https://docs.sympy.org/latest/index.html"

    def mathExpressionSymPyDocsUrlVersionResource(self, version: str) -> str:
        """
        SymPy documentation URL resource version.

        Args:
            version: the version.

        Return:
            the resource result.
        """
        return f"The document version {version}"

    def register(self) -> bool:
        """
        register all tools, prompts, resources.

        Return:
            true if registered; else false.
        """
        registeredAll: bool = True

        # ternary conditional statement.
        # register tools.
        registeredAll = True if (self.registerTool_MathExpressionEvaluator() and registeredAll) else False
        registeredAll = True if (self.registerPrompt_MathExpressionEvaluator() and registeredAll) else False
        registeredAll = True if (self.registerPrompt_MathExpressionResult() and registeredAll) else False
        registeredAll = True if (self.registerResource_SymPyDocsUrl() and registeredAll) else False
        registeredAll = True if (self.registerResource_SymPyDocsUrl_Version() and registeredAll) else False

        # if all registered.
        return registeredAll

    def getPromptHelpers(self) -> List[McpPromptHelper]:
        """
        get the list of prompt helpers.

        Return:
            the list of prompt helpers.
        """
        prompts: List[McpPromptHelper] = []

        # add prompt.
        prompts.append(McpPromptHelper(
            "MathExpressionEvaluator",
            "evaluate the math expression: {expression}"
        ))

        prompts.append(McpPromptHelper(
            "MathExpressionResult",
            "describe the result: {result}, using latex"
        ))

        # return the helper list.
        return prompts

# if main.
def mainSymPyMathServer(useStreamableHttp: bool = False) -> SymPyMath | None:
    """
    start the SymPy math server.

    Args:
            useStreamableHttp:    use streamable HTTP to receiving messages.
    """
    # start server.
    sympymath_server = SymPyMath()

    # if registered
    if (sympymath_server.register()):
        # start server.
        if (useStreamableHttp):
            sympymath_server.startServerHttp()
        else:
            sympymath_server.startServerStdio()

        # return the server.
        return sympymath_server
    else:
        return None
```
