Make the Tulip MCP server easier to interact with

,

I found out about the Tulip MCP server today and decided to try and get it going. Unfortunately the main LLM chat client I have is Open WebUI which is looking for a REST based server.

It turns out they have a proxy server, mcpo that directly addresses this issue.

Therefore I filed the following github issue to see if it could be incorporated:

Hey @Richard-SNN -

Thanks for the suggestion - we just merged a change to the repo that allows the Tulip MCP to be runnable via npx. Npx is natively supported by the official mcpo-docker package, and this would expose a Open WebUI compatible interface for working with the Tulip MCP.

For example, this command will work out of the box -

docker run -p 8000:8000 \
  -v /path-to-my/.env:/.env \
  ghcr.io/open-webui/mcpo:main \
  --api-key "top-secret" \
  -- npx @tulip/mcp-server

Pete

I can’t tell if this is an mcpo error or Tulip MCP server error:

$ podman run --privileged -p 8001:8000  -v ./tulip-mcp/.env:/app/.env   ghcr.io/open-webui/mcpo:main   --api-key "top-secret"   -- npx @tulip/mcp-server
2025-06-23 17:36:09,463 - INFO - Starting MCPO Server...
2025-06-23 17:36:09,464 - INFO -   Name: MCP OpenAPI Proxy
2025-06-23 17:36:09,464 - INFO -   Version: 1.0
2025-06-23 17:36:09,464 - INFO -   Description: Automatically generated API from MCP Tool Schemas
2025-06-23 17:36:09,464 - INFO -   Hostname: b83c8ea0af93
2025-06-23 17:36:09,464 - INFO -   Port: 8000
2025-06-23 17:36:09,464 - INFO -   API Key: Provided
2025-06-23 17:36:09,464 - INFO -   CORS Allowed Origins: ['*']
2025-06-23 17:36:09,464 - INFO -   Path Prefix: /
2025-06-23 17:36:09,464 - INFO - Configuring for a single Stdio MCP Server with command: npx @tulip/mcp-server
2025-06-23 17:36:09,464 - INFO - Uvicorn server starting...
INFO:     Started server process [1]
INFO:     Waiting for application startup.
npm warn exec The following package was not found and will be installed: @tulip/mcp-server@1.1.2
npm warn deprecated node-domexception@1.0.0: Use your platform's native DOMException instead
📚 Loaded 71 tool definitions from JSON files
ERROR:      + Exception Group Traceback (most recent call last):
  |   File "/app/.venv/lib/python3.11/site-packages/starlette/routing.py", line 692, in lifespan
  |     async with self.lifespan_context(app) as maybe_state:
  |   File "/usr/lib/python3.11/contextlib.py", line 204, in __aenter__
  |     return await anext(self.gen)
  |            ^^^^^^^^^^^^^^^^^^^^^
  |   File "/app/.venv/lib/python3.11/site-packages/mcpo/main.py", line 114, in lifespan
  |     async with stdio_client(server_params) as (reader, writer):
  |   File "/usr/lib/python3.11/contextlib.py", line 222, in __aexit__
  |     await self.gen.athrow(typ, value, traceback)
  |   File "/app/.venv/lib/python3.11/site-packages/mcp/client/stdio/__init__.py", line 178, in stdio_client
  |     async with (
  |   File "/app/.venv/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 772, in __aexit__
  |     raise BaseExceptionGroup(
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Exception Group Traceback (most recent call last):
    |   File "/app/.venv/lib/python3.11/site-packages/mcp/client/stdio/__init__.py", line 185, in stdio_client
    |     yield read_stream, write_stream
    |   File "/app/.venv/lib/python3.11/site-packages/mcpo/main.py", line 115, in lifespan
    |     async with ClientSession(reader, writer) as session:
    |   File "/app/.venv/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 772, in __aexit__
    |     raise BaseExceptionGroup(
    | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
    +-+---------------- 1 ----------------
      | Traceback (most recent call last):
      |   File "/app/.venv/lib/python3.11/site-packages/mcpo/main.py", line 117, in lifespan
      |     await create_dynamic_endpoints(app, api_dependency=api_dependency)
      |   File "/app/.venv/lib/python3.11/site-packages/mcpo/main.py", line 53, in create_dynamic_endpoints
      |     form_model_fields = get_model_fields(
      |                         ^^^^^^^^^^^^^^^^^
      |   File "/app/.venv/lib/python3.11/site-packages/mcpo/utils/main.py", line 219, in get_model_fields
      |     python_type_hint, pydantic_field_info = _process_schema_property(
      |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^
      |   File "/app/.venv/lib/python3.11/site-packages/mcpo/utils/main.py", line 187, in _process_schema_property
      |     item_type_hint, _ = _process_schema_property(
      |                         ^^^^^^^^^^^^^^^^^^^^^^^^^
      |   File "/app/.venv/lib/python3.11/site-packages/mcpo/utils/main.py", line 175, in _process_schema_property
      |     NestedModel = create_model(nested_model_name, **nested_fields)
      |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |   File "/app/.venv/lib/python3.11/site-packages/pydantic/main.py", line 1763, in create_model
      |     return meta(
      |            ^^^^^
      |   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_model_construction.py", line 112, in __new__
      |     private_attributes = inspect_namespace(
      |                          ^^^^^^^^^^^^^^^^^^
      |   File "/app/.venv/lib/python3.11/site-packages/pydantic/_internal/_model_construction.py", line 434, in inspect_namespace
      |     raise NameError(
      | NameError: Fields must not use names with leading underscores; e.g., use 'id' instead of '_id'.
      +------------------------------------

ERROR:    Application startup failed. Exiting.
Starting MCP OpenAPI Proxy on 0.0.0.0:8000 with command: npx @tulip/mcp-server

Hi @Richard-SNN!

It looks like the error is in mcpo’s handling of field names:

NameError: Fields must not use names with leading underscores; e.g., use ‘id’ instead of ‘_id’.

It appears that this was fixed in the mcpo project a couple of weeks ago; can you try pulling the latest image (podman pull ghcr.io/open-webui/mcpo:main, I think?) and seeing if that fixes this for you? I just spun up Open WebUI locally in Docker with with the mcpo-wrapped Tulip MCP, and didn’t see any issues with the field names.

I did try using an old version of mcpo, though, and still didn’t see the issue, so there might be something else going wrong here.

1 Like

Did some more investigation, and it seems that mcpo does still have an issue with fields starting with underscores, which two of the tools do use. I didn’t run into this with my test, because I was only using read-only tools, and these two tools are write-able tools.

These two tools are createTableQuery and updateTableQuery. If you don’t need access to either of those two tools for now, it’s possible to include all of the other tools manually as a workaround.

It’s not the most elegant workaround, since there are 71 tools(!) available at the moment with most of those being table tools, so you’d have to set your ENABLED_TOOLS to something like this if you wanted to enable everything except those two tools.

ENABLED_TOOLS=interface,station,station-group,machine,app,user,utility,createTable,createTableAggregation,createTableLink,createTableRecord,deleteAllTableRecords,deleteTableAggregation,deleteTableQuery,deleteTableRecord,getTable,getTableAggregation,getTableLink,getTableQuery,getTableRecord,incrementTableRecordField,linkTableRecords,listTableAggregations,listTableQueries,listTableRecords,listTables,runTableAggregation,unlinkTableRecords,updateTable,updateTableAggregation,updateTableLinkLabels,updateTableRecord

I can take a look soon to see if this is something that can/should be fixed in mcpo or if there is something we would need to do to our tool definitions to work around this on the Tulip MCP side.

1 Like