-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
567 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
plugin.wasm | ||
plugin/__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Python Eval Servlet | ||
|
||
A simple servlet that evaluates Python code in a CPython Wasm sandbox and returns the result. | ||
|
||
## What it does | ||
|
||
Takes Python code as input, evaluates it using `exec()`, and returns the stdout output as a string. | ||
|
||
## Usage | ||
|
||
Call with: | ||
|
||
```json | ||
{ | ||
"arguments": { | ||
"code": "print(2 + 2)" // Required: Python code to evaluate | ||
} | ||
} | ||
``` | ||
|
||
Returns: | ||
|
||
``` | ||
4 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# THIS FILE WAS GENERATED BY `xtp-python-bindgen`. DO NOT EDIT. | ||
|
||
from typing import Optional, List # noqa: F401 | ||
from datetime import datetime # noqa: F401 | ||
import json | ||
import extism # pyright: ignore | ||
import plugin | ||
|
||
|
||
from pdk_types import ( | ||
BlobResourceContents, | ||
CallToolRequest, | ||
CallToolResult, | ||
Content, | ||
ContentType, | ||
ListToolsResult, | ||
Params, | ||
Role, | ||
TextAnnotation, | ||
TextResourceContents, | ||
ToolDescription, | ||
) # noqa: F401 | ||
|
||
|
||
# Imports | ||
|
||
|
||
# Exports | ||
# The implementations for these functions is in `plugin.py` | ||
|
||
|
||
# Called when the tool is invoked. | ||
# If you support multiple tools, you must switch on the input.params.name to detect which tool is being called. | ||
@extism.plugin_fn | ||
def call(): | ||
input = extism.input_str() | ||
input = CallToolRequest.from_json(input) | ||
res = plugin.call(input) | ||
extism.output_str(res.to_json()) | ||
|
||
|
||
# Called by mcpx to understand how and why to use this tool. | ||
# Note: Your servlet configs will not be set when this function is called, | ||
# so do not rely on config in this function | ||
@extism.plugin_fn | ||
def describe(): | ||
res = plugin.describe() | ||
extism.output_str(res.to_json()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# THIS FILE WAS GENERATED BY `xtp-python-bindgen`. DO NOT EDIT. | ||
|
||
from typing import Optional, List # noqa: F401 | ||
from datetime import datetime # noqa: F401 | ||
import extism # noqa: F401 # pyright: ignore | ||
import json | ||
|
||
|
||
from pdk_types import ( | ||
BlobResourceContents, | ||
CallToolRequest, | ||
CallToolResult, | ||
Content, | ||
ContentType, | ||
ListToolsResult, | ||
Params, | ||
Role, | ||
TextAnnotation, | ||
TextResourceContents, | ||
ToolDescription, | ||
) # noqa: F401 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
# THIS FILE WAS GENERATED BY `xtp-python-bindgen`. DO NOT EDIT. | ||
|
||
from __future__ import annotations | ||
from enum import Enum # noqa: F401 | ||
from typing import Optional, List # noqa: F401 | ||
from datetime import datetime # noqa: F401 | ||
from dataclasses import dataclass # noqa: F401 | ||
from dataclass_wizard import JSONWizard # noqa: F401 | ||
from dataclass_wizard.type_def import JSONObject | ||
from base64 import b64encode, b64decode | ||
|
||
|
||
@dataclass | ||
class BlobResourceContents(JSONWizard): | ||
# A base64-encoded string representing the binary data of the item. | ||
blob: str | ||
|
||
# The URI of this resource. | ||
uri: str | ||
|
||
# The MIME type of this resource, if known. | ||
mimeType: Optional[str] = None | ||
|
||
@classmethod | ||
def _pre_from_dict(cls, o: JSONObject) -> JSONObject: | ||
return o | ||
|
||
def _pre_dict(self): | ||
return | ||
|
||
|
||
@dataclass | ||
class CallToolRequest(JSONWizard): | ||
params: Params | ||
|
||
method: Optional[str] = None | ||
|
||
@classmethod | ||
def _pre_from_dict(cls, o: JSONObject) -> JSONObject: | ||
return o | ||
|
||
def _pre_dict(self): | ||
return | ||
|
||
|
||
@dataclass | ||
class CallToolResult(JSONWizard): | ||
content: List[Content] | ||
|
||
# Whether the tool call ended in an error. | ||
# | ||
# If not set, this is assumed to be false (the call was successful). | ||
isError: Optional[bool] = None | ||
|
||
@classmethod | ||
def _pre_from_dict(cls, o: JSONObject) -> JSONObject: | ||
return o | ||
|
||
def _pre_dict(self): | ||
return | ||
|
||
|
||
@dataclass | ||
class Content(JSONWizard): | ||
type: ContentType | ||
|
||
annotations: Optional[TextAnnotation] = None | ||
|
||
# The base64-encoded image data. | ||
data: Optional[str] = None | ||
|
||
# The MIME type of the image. Different providers may support different image types. | ||
mimeType: Optional[str] = None | ||
|
||
# The text content of the message. | ||
text: Optional[str] = None | ||
|
||
@classmethod | ||
def _pre_from_dict(cls, o: JSONObject) -> JSONObject: | ||
return o | ||
|
||
def _pre_dict(self): | ||
return | ||
|
||
|
||
class ContentType(Enum): | ||
Text = "text" | ||
Image = "image" | ||
Resource = "resource" | ||
|
||
|
||
@dataclass | ||
class ListToolsResult(JSONWizard): | ||
# The list of ToolDescription objects provided by this servlet. | ||
tools: List[ToolDescription] | ||
|
||
@classmethod | ||
def _pre_from_dict(cls, o: JSONObject) -> JSONObject: | ||
return o | ||
|
||
def _pre_dict(self): | ||
return | ||
|
||
|
||
@dataclass | ||
class Params(JSONWizard): | ||
name: str | ||
|
||
arguments: Optional[dict] = None | ||
|
||
@classmethod | ||
def _pre_from_dict(cls, o: JSONObject) -> JSONObject: | ||
return o | ||
|
||
def _pre_dict(self): | ||
return | ||
|
||
|
||
class Role(Enum): | ||
Assistant = "assistant" | ||
User = "user" | ||
|
||
|
||
@dataclass | ||
class TextAnnotation(JSONWizard): | ||
# Describes who the intended customer of this object or data is. | ||
# | ||
# It can include multiple entries to indicate content useful for multiple audiences (e.g., `["user", "assistant"]`). | ||
audience: Optional[List[Role]] = None | ||
|
||
# Describes how important this data is for operating the server. | ||
# | ||
# A value of 1 means "most important," and indicates that the data is | ||
# effectively required, while 0 means "least important," and indicates that | ||
# the data is entirely optional. | ||
priority: Optional[float] = None | ||
|
||
@classmethod | ||
def _pre_from_dict(cls, o: JSONObject) -> JSONObject: | ||
return o | ||
|
||
def _pre_dict(self): | ||
return | ||
|
||
|
||
@dataclass | ||
class TextResourceContents(JSONWizard): | ||
# The text of the item. This must only be set if the item can actually be represented as text (not binary data). | ||
text: str | ||
|
||
# The URI of this resource. | ||
uri: str | ||
|
||
# The MIME type of this resource, if known. | ||
mimeType: Optional[str] = None | ||
|
||
@classmethod | ||
def _pre_from_dict(cls, o: JSONObject) -> JSONObject: | ||
return o | ||
|
||
def _pre_dict(self): | ||
return | ||
|
||
|
||
@dataclass | ||
class ToolDescription(JSONWizard): | ||
# A description of the tool | ||
description: str | ||
|
||
# The JSON schema describing the argument input | ||
inputSchema: dict | ||
|
||
# The name of the tool. It should match the plugin / binding name. | ||
name: str | ||
|
||
@classmethod | ||
def _pre_from_dict(cls, o: JSONObject) -> JSONObject: | ||
return o | ||
|
||
def _pre_dict(self): | ||
return |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
from typing import Optional, List # noqa: F401 | ||
from datetime import datetime # noqa: F401 | ||
import extism # noqa: F401 # pyright: ignore | ||
import traceback | ||
from io import StringIO | ||
import sys | ||
|
||
from pdk_types import ( | ||
BlobResourceContents, | ||
CallToolRequest, | ||
CallToolResult, | ||
Content, | ||
ContentType, | ||
ListToolsResult, | ||
Params, | ||
Role, | ||
TextAnnotation, | ||
TextResourceContents, | ||
ToolDescription, | ||
) # noqa: F401 | ||
|
||
|
||
from typing import List, Optional # noqa: F401 | ||
|
||
|
||
# Called when the tool is invoked. | ||
# If you support multiple tools, you must switch on the input.params.name to detect which tool is being called. | ||
def call(input: CallToolRequest) -> CallToolResult: | ||
try: | ||
code = input.params.arguments['code'] | ||
output = StringIO() | ||
old_stdout = sys.stdout | ||
sys.stdout = output | ||
exec(code) | ||
sys.stdout = old_stdout | ||
result = output.getvalue() | ||
output.close() | ||
isError = False | ||
except Exception as e: | ||
result = "\n".join([ | ||
"Traceback (most recent call last):", | ||
traceback.format_tb(e.__traceback__)[0].rstrip(), | ||
f"{type(e).__name__}: {e}" | ||
]) | ||
isError = True | ||
return CallToolResult( | ||
content=[ | ||
Content( | ||
text=result, | ||
mimeType="text/plain", | ||
type=ContentType.Text, | ||
annotations=None, | ||
data=None, | ||
) | ||
], | ||
isError=isError, | ||
) | ||
|
||
# Called by mcpx to understand how and why to use this tool. | ||
# Note: Your servlet configs will not be set when this function is called, | ||
# so do not rely on config in this function | ||
def describe() -> ListToolsResult: | ||
return ListToolsResult( | ||
[ | ||
ToolDescription( | ||
name="eval-py", | ||
description="Evaluate some Python using `exec()` in a sandbox.", | ||
inputSchema={ | ||
"type": "object", | ||
"properties": { | ||
"code": { | ||
"type": "string", | ||
"description": "The Python code to eval. This code gets passed into `exec()` and the stdout output is returned.", | ||
}, | ||
}, | ||
"required": ["code"], | ||
}, | ||
) | ||
] | ||
) |
Oops, something went wrong.