RFC for internal MCP server in substitution of the current go version#232
RFC for internal MCP server in substitution of the current go version#232chargio wants to merge 6 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds an RFC describing a proposed migration from the current external Go-based MCP server to an internal Elixir/Phoenix-hosted MCP server, aiming to simplify deployment and reduce duplicated tooling between Trento and the internal agent (Liz).
Changes:
- Introduces RFC 0005 outlining motivation, security model, and configuration implications for an internal MCP server.
- Compares current Go MCP bridge configuration with an internal Anubis-based approach.
- Documents migration caveats and endpoint/configuration considerations.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -0,0 +1,140 @@ | |||
| == 1. Migrate to internal MCP server | |||
There was a problem hiding this comment.
Fixed in commit — renamed the file to 0005-migrate-to-internal-mcp-server.adoc to correct the "sever" typo and align casing with the other RFC filenames.
| THe current MCP server is a Go application that implements the MCP protocol, and it is used by the external agent to communicate with Trento. Installing the MCP server requires indepedent configuration and connection to an existing installation, introducing a bigger attack surface and configuration problems. The Trento MCP server requires: | ||
| - A running Trento server (version 3.x or later). | ||
| - An MCP-Compatible AI assitant | ||
| - A Trento Personal Access Token (PAT), generated from your Trento user profile for secure API access. |
| - A Trento Personal Access Token (PAT), generated from your Trento user profile for secure API access. | ||
| - Configuration in /etc/trento/mcp-server-trento | ||
|
|
||
| The Trento MCP server today is a Go applcation, that acts as a bridge between the MCP clients and the Trento API, automatically generating MCP tools from the OpenAPI specification. |
| You can run an MCP server directly using on the native Elixir MCP packages. The two main packages are: | ||
|
|
||
| - `annubis_mcp`` (formely `hermes_mcp`). A comprehensive, production-ready SDK that supports STDIO (for local clients) and SSE/HTTP (for remote/web clients). It allows for the dynamic registration of tools. | ||
| - `emcp`. A minimalistic, lightweight MCP client/server library designed to be mounted directly as a Plug in your phoenix router. |
| - `annubis_mcp`` (formely `hermes_mcp`). A comprehensive, production-ready SDK that supports STDIO (for local clients) and SSE/HTTP (for remote/web clients). It allows for the dynamic registration of tools. | ||
| - `emcp`. A minimalistic, lightweight MCP client/server library designed to be mounted directly as a Plug in your phoenix router. | ||
|
|
||
| Wse also considered using Nodejs, building a tiny Node MCP server, using the official `@modelcontextprotocol/sdk`to build a server that fetches tool definitino for the Elixir backend and proxies execution requests back to an Elixir endpoint. |
| [cols="3,1,6", options="header"] | ||
| |=== | ||
| |Environmental variables | default value | Detail | ||
| | TRENTO_MCP_ENABLEED | false | Whether the internal MCP server is enabled or not. If false, the internal MCP server will not be started. |
|
|
||
| 3. There is no way to install the MCP server into a separate applcation. By design, the internal MCP server is part of the Trento application, and it is not possible to install it into a separate application. | ||
|
|
||
| 4. You can't use command-line flags to configure the internal MCP server. THe configuration is done via de Elixir config files or environmental variables. Additional UX design should be done to include them as part of the command line for Trento itself. |
| * As a user, I want to have a similar experience when I am using the internal AI agent (Liz) and when I am using the external MCP agent, so that I can use Trento in a consistent way. | ||
| * As a user, I want to be able to enable/disable the MCP server | ||
| * As a user, I want to be able to configure the MCP server. | ||
| * As a user, I want to use MCPHost to connect to the MCP server in SLES 16. |
There was a problem hiding this comment.
| * As a user, I want to use MCPHost to connect to the MCP server in SLES 16. | |
| * As a user, I want to use MCPHost/Kit to connect to the MCP server in SLES 16. |
There was a problem hiding this comment.
question: are we talking about https://github.com/mark3labs/mcphost and https://github.com/mark3labs/kit? Or something else?
Let's add a reference in any case.
|
|
||
| THe current MCP server is a Go application that implements the MCP protocol, and it is used by the external agent to communicate with Trento. Installing the MCP server requires indepedent configuration and connection to an existing installation, introducing a bigger attack surface and configuration problems. The Trento MCP server requires: | ||
| - A running Trento server (version 3.x or later). | ||
| - An MCP-Compatible AI assitant |
There was a problem hiding this comment.
| - An MCP-Compatible AI assitant | |
| - An MCP-Compatible AI assistant (MCP client) |
| * define the changes required to migrate to an internal MCP server, and what would be the tradeoffs. | ||
| * define a migration path to move from the current MCP server to the new internal one. | ||
|
|
||
| THe current MCP server is a Go application that implements the MCP protocol, and it is used by the external agent to communicate with Trento. Installing the MCP server requires indepedent configuration and connection to an existing installation, introducing a bigger attack surface and configuration problems. The Trento MCP server requires: |
There was a problem hiding this comment.
| THe current MCP server is a Go application that implements the MCP protocol, and it is used by the external agent to communicate with Trento. Installing the MCP server requires indepedent configuration and connection to an existing installation, introducing a bigger attack surface and configuration problems. The Trento MCP server requires: | |
| The current MCP server is a Go application that implements the MCP protocol, and it is used by the external agent to communicate with Trento. Installing the MCP server requires independent configuration and connection to an existing installation, introducing a bigger attack surface and configuration problems. The Trento MCP server requires: |
| - A Trento Personal Access Token (PAT), generated from your Trento user profile for secure API access. | ||
| - Configuration in /etc/trento/mcp-server-trento | ||
|
|
||
| The Trento MCP server today is a Go applcation, that acts as a bridge between the MCP clients and the Trento API, automatically generating MCP tools from the OpenAPI specification. |
There was a problem hiding this comment.
| The Trento MCP server today is a Go applcation, that acts as a bridge between the MCP clients and the Trento API, automatically generating MCP tools from the OpenAPI specification. | |
| The Trento MCP server today is a Go application that acts as a bridge between the MCP clients and the Trento API, automatically generating MCP tools from the OpenAPI specification. |
|
|
||
| The Trento MCP server today is a Go applcation, that acts as a bridge between the MCP clients and the Trento API, automatically generating MCP tools from the OpenAPI specification. | ||
|
|
||
| The trento MCP server generates a list of tools based on the OpenAPI specification, using labels to define which tools are available for the MCP clients. |
There was a problem hiding this comment.
note: for that we actually use a 3rd-party dependency, https://pkg.go.dev/github.com/evcc-io/openapi-mcp, to which we usually contribute whenever we find bugs... but it is not widely used right now.
There was a problem hiding this comment.
I've added the link to the text.
| - `annubis_mcp`` (formely `hermes_mcp`). A comprehensive, production-ready SDK that supports STDIO (for local clients) and SSE/HTTP (for remote/web clients). It allows for the dynamic registration of tools. | ||
| - `emcp`. A minimalistic, lightweight MCP client/server library designed to be mounted directly as a Plug in your phoenix router. | ||
|
|
||
| Wse also considered using Nodejs, building a tiny Node MCP server, using the official `@modelcontextprotocol/sdk`to build a server that fetches tool definitino for the Elixir backend and proxies execution requests back to an Elixir endpoint. |
There was a problem hiding this comment.
| Wse also considered using Nodejs, building a tiny Node MCP server, using the official `@modelcontextprotocol/sdk`to build a server that fetches tool definitino for the Elixir backend and proxies execution requests back to an Elixir endpoint. | |
| We also considered using Node.js, building a tiny Node MCP server, using the official `@modelcontextprotocol/sdk`to build a server that fetches tool definitions for the Elixir backend and proxies execution requests back to an Elixir endpoint. |
| The Go mcp-server acts as a multi-user proxy between the client (your IDE or agent) and the Elixir trento-web API. The job of the MCP is to fetch OpenAPI specs | ||
|
|
||
| * *Token Delivery*: The MCP client (e.g., VS Code or Claude Desktop) is configured with an Authorization header containing the user's Trento Personal Access Token (PAT). | ||
| * *Session Mapping*: When the client initializes the connection (via SSE/HTTP), the Go mcp-server intercepts the header, associates the PAT with the unique sessionID, and stores it. |
There was a problem hiding this comment.
note: the next protocol version is supposed to be totally stateless, so this is gonna become a problem if we want to support it.
There was a problem hiding this comment.
Currently we use a PAT to do the same, so the problem would be anyway present, and we will need to solve it anyway for Liz
There was a problem hiding this comment.
+1 regardless of the implementation, whether the current external artifact or the embedded one, when connecting to trento's mcp server the user needs to be identified, in order to authorize operations.
I would imagine that a user still needs to configure the MCP client by providing the MCP server url and some additional config, where I imagine the PAT would still be a thing.
What are the main concerns here? What am I missing? Is OAuth/OIDC involved in the topic? If so we're going to open a pandora box 🙈
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Update version numbers after June patch release
* Add information about trentoWeb.origin parameter * Include SME feedback
|
|
||
|
|
||
| == Additional considerations | ||
| - It would be optional to create a solution that can provide the MCP server as an application inside the BEAM (umbrella application). In that case, it would be possible to define via configuration if the MCP server is started or not, and it would be possible to run it standalone. In an umbrella application, tests for each application are independent. Umbrella applications would imply additional complexity, and it is not clear if it would be worth the effort. The current proposal is to have the MCP server as part of the Trento application, and it would be started automatically when Trento is started. An application inside the BEAM would be a nice to have, but it would require additional work to transition from a single application to a series of applications, in which case the MCP would be one of them. |
There was a problem hiding this comment.
This RFC does not motivate the 'why' of the umbrella application solution. Why do you think the umbrella application solution (exlusively, perhaps ?) addresses some issues that the current trento-web application architecture does not or can not? Can you also please clarify if you want/are proposing a separate deploy-able artifact for the umbrella members?
There was a problem hiding this comment.
That is not part of the RFC, it is something to consider for the future.
It would allow to test the MCP server indepednently of the rest. And start the application only when needed
There was a problem hiding this comment.
+1 in deferring further discussions about umbrella application.
| == Additional considerations | ||
| - It would be optional to create a solution that can provide the MCP server as an application inside the BEAM (umbrella application). In that case, it would be possible to define via configuration if the MCP server is started or not, and it would be possible to run it standalone. In an umbrella application, tests for each application are independent. Umbrella applications would imply additional complexity, and it is not clear if it would be worth the effort. The current proposal is to have the MCP server as part of the Trento application, and it would be started automatically when Trento is started. An application inside the BEAM would be a nice to have, but it would require additional work to transition from a single application to a series of applications, in which case the MCP would be one of them. | ||
|
|
||
| - The endpoint is currently defined as `trento-server/mcp-server_endpoint/mcp`. It would make sense to simplify the endpoint to be `trento-server/mcp`, as the endpoint is already defined in the Trento application, and it is not necessary to have a separate endpoint for the MCP server. The current proposal is to keep the endpoint as it is, but it would be nice to have a simpler endpoint or even double it and deprecate the old one. No newline at end of file |
There was a problem hiding this comment.
Can you please explain how is this consideration consistent with the desire/need to have a configurableTRENTO_MCP_PORT?
There was a problem hiding this comment.
The current solution is puslished at the trento-server/mcp-server_endpoint/mcp endpoint in port 5000. With the new to decide if we want to have it in the same port or we want to have it in a different port (no longer needed as the pipeline is the same and not a different component in the same system requiring a separate port)
There was a problem hiding this comment.
I also noticed the same inconsistency and left a similar related comment elsewhere.
TLDR: I don't see, yet, a need to have a different endpoint (as in the Phoenix.Endpoint meaning) for the embedded mcp server. It could very well be a route in the current endpoint.
Unless I am missing something.
| == Additional considerations | ||
| - It would be optional to create a solution that can provide the MCP server as an application inside the BEAM (umbrella application). In that case, it would be possible to define via configuration if the MCP server is started or not, and it would be possible to run it standalone. In an umbrella application, tests for each application are independent. Umbrella applications would imply additional complexity, and it is not clear if it would be worth the effort. The current proposal is to have the MCP server as part of the Trento application, and it would be started automatically when Trento is started. An application inside the BEAM would be a nice to have, but it would require additional work to transition from a single application to a series of applications, in which case the MCP would be one of them. | ||
|
|
||
| - The endpoint is currently defined as `trento-server/mcp-server_endpoint/mcp`. It would make sense to simplify the endpoint to be `trento-server/mcp`, as the endpoint is already defined in the Trento application, and it is not necessary to have a separate endpoint for the MCP server. The current proposal is to keep the endpoint as it is, but it would be nice to have a simpler endpoint or even double it and deprecate the old one. No newline at end of file |
There was a problem hiding this comment.
Can you please explain further what would "even double it and deprecate the old one" mean in more concrete terms?
There was a problem hiding this comment.
We can have both endpoints available in routes, the existing one and the simplified ones, pointing to the same application.
Then we can deprecate the old one and migrate in time to the new one.
| |Environment variable | default value | Detail | ||
| | TRENTO_MCP_ENABLED | false | Whether the internal MCP server is enabled or not. If false, the internal MCP server will not be started. | ||
| | TRENTO_MCP_PORT | 5000 | The port on which the MCP server listens for incoming connections with HTTP transport | ||
| | TRENTO_MCP_LOG_LEVEL | info | The verbosity level of the MCP server logs. Possible values are: debug, info, warn, error |
There was a problem hiding this comment.
Any thoughts/opinions on mapping MCP server logs to ActivityLogs?
There was a problem hiding this comment.
Can you ellaborate?
There was a problem hiding this comment.
Activity log is not related to the mentioned log level here. I understand we are talking about application logs.
Besides this, in the context of an elixir embedded MCP server I would start by only relying on the global web logger and its configuration.
Yes, I believe we can configure multiple loggers and what not, it's just a matter of avoiding accidental complexity where we have more than enough inherent complexity 😅
nelsonkopliku
left a comment
There was a problem hiding this comment.
Thanks @chargio for the effort.
I am assuming that this RFC is coming from a clarification of the fact that from a broader product perspective we DO NOT NEED a separate artifact called mcp-server-trento
If that is the case then TLDR:
I think the idea of simplifying the overall system by embedding the mcp server inside trento-web would have several benefits:
- for customers as they would have less operational burden
- for us as we would improve maintainability
- for the feature stability as it would reduce the networking roundtrip needed with the current proxy
However, as mentioned in the long-ish comment inline I believe this is a delicate decision that requires even more careful thinking and iteration on actual options.
If there was an expectation for this to happen before trento 3.2, I am afraid we will need to revisit that expectation.
Happy to discuss more, either in this RFC and/or sync.
|
|
||
| * As a user, I want to be able to publish capabilities of Trento using the MCP protocol, so that it can be used by an external agent. | ||
| * As a user, I want to have a similar experience when I am using the internal AI agent (Liz) and when I am using the external MCP agent, so that I can use Trento in a consistent way. | ||
| * As a user, I want to be able to enable/disable the MCP server |
There was a problem hiding this comment.
note: we need to define whether the MCP server is enabled/disabled at startup via env variables or via UI.
| * As a user, I want to be able to publish capabilities of Trento using the MCP protocol, so that it can be used by an external agent. | ||
| * As a user, I want to have a similar experience when I am using the internal AI agent (Liz) and when I am using the external MCP agent, so that I can use Trento in a consistent way. | ||
| * As a user, I want to be able to enable/disable the MCP server | ||
| * As a user, I want to be able to configure the MCP server. |
There was a problem hiding this comment.
question: what kind of configuration does this entail?
Is it about configuring the endpoint/port where the MCP server listens to, if even necessary? Or is it about configuring which tools are exposed?
| * As a user, I want to have a similar experience when I am using the internal AI agent (Liz) and when I am using the external MCP agent, so that I can use Trento in a consistent way. | ||
| * As a user, I want to be able to enable/disable the MCP server | ||
| * As a user, I want to be able to configure the MCP server. | ||
| * As a user, I want to use MCPHost to connect to the MCP server in SLES 16. |
There was a problem hiding this comment.
question: are we talking about https://github.com/mark3labs/mcphost and https://github.com/mark3labs/kit? Or something else?
Let's add a reference in any case.
| * As a user, I want to be able to enable/disable the MCP server | ||
| * As a user, I want to be able to configure the MCP server. | ||
| * As a user, I want to use MCPHost to connect to the MCP server in SLES 16. | ||
| * As a user, I want to use both streamable and sse as the transport protocols for the MCP server, so that I can use the one that is more suitable for my environment. |
There was a problem hiding this comment.
suggestion: in latest MCP spec, SSE seems to be the legacy way https://modelcontextprotocol.io/specification/2025-11-25/basic/transports.
Let's agree which transport we should support.
| * As a user, I want to be able to configure the MCP server. | ||
| * As a user, I want to use MCPHost to connect to the MCP server in SLES 16. | ||
| * As a user, I want to use both streamable and sse as the transport protocols for the MCP server, so that I can use the one that is more suitable for my environment. | ||
| * As a developer, I want to reduce the maintenance needed for the alignment of tools used by Liz and by the MCP server, so that the customer gets the same capabilities and responses independently of how they use it. |
There was a problem hiding this comment.
note: this is already the case currently. "MCP" tagged open api endpoints become automatically available tools to MCP server and Liz implementation.
|
|
||
| 1. The Go bridge that we were using before gives you the API for free, only taking into account the tags required to expose it. Using Anubis in Elixir is already automated. The same "MCP" tags used in the Trento server are used to configure the AI assistant's toolset and so that they continue being aligned automatically. The only new work is the authentication plug. | ||
|
|
||
| 2. Additional work needs to be done to add a health check endpoint to the internal MCP server, as the current health check is done by the Go bridge. The health check should be implemented in Elixir, reusing the existing liveness/readiness endpoints. |
There was a problem hiding this comment.
question: besides the fact that removing the extra artifact clearly removes also all it involves, in the context of an embedded mcp server in trento web, what would the existing /healthz and /readyz endpoints need to do differently?
|
|
||
| 2. Additional work needs to be done to add a health check endpoint to the internal MCP server, as the current health check is done by the Go bridge. The health check should be implemented in Elixir, reusing the existing liveness/readiness endpoints. | ||
|
|
||
| 3. There is no way to install the MCP server as a separate application. By design, the internal MCP server is part of the Trento application, and it is not possible to install it separately. |
There was a problem hiding this comment.
nit: not necessary content IMHO, the whole RFC is about removing a separate application.
|
|
||
| 3. There is no way to install the MCP server as a separate application. By design, the internal MCP server is part of the Trento application, and it is not possible to install it separately. | ||
|
|
||
| 4. You can't use command-line flags to configure the internal MCP server. The configuration is done via the Elixir config files or environment variables. Additional UX design should be done to include them as part of the command line for Trento itself. |
There was a problem hiding this comment.
nit: not necessary content IMHO. The what and the how about configuration is an implementation detail at this stage.
|
|
||
|
|
||
| == Additional considerations | ||
| - It would be optional to create a solution that can provide the MCP server as an application inside the BEAM (umbrella application). In that case, it would be possible to define via configuration if the MCP server is started or not, and it would be possible to run it standalone. In an umbrella application, tests for each application are independent. Umbrella applications would imply additional complexity, and it is not clear if it would be worth the effort. The current proposal is to have the MCP server as part of the Trento application, and it would be started automatically when Trento is started. An application inside the BEAM would be a nice to have, but it would require additional work to transition from a single application to a series of applications, in which case the MCP would be one of them. |
There was a problem hiding this comment.
+1 in deferring further discussions about umbrella application.
| == Additional considerations | ||
| - It would be optional to create a solution that can provide the MCP server as an application inside the BEAM (umbrella application). In that case, it would be possible to define via configuration if the MCP server is started or not, and it would be possible to run it standalone. In an umbrella application, tests for each application are independent. Umbrella applications would imply additional complexity, and it is not clear if it would be worth the effort. The current proposal is to have the MCP server as part of the Trento application, and it would be started automatically when Trento is started. An application inside the BEAM would be a nice to have, but it would require additional work to transition from a single application to a series of applications, in which case the MCP would be one of them. | ||
|
|
||
| - The endpoint is currently defined as `trento-server/mcp-server_endpoint/mcp`. It would make sense to simplify the endpoint to be `trento-server/mcp`, as the endpoint is already defined in the Trento application, and it is not necessary to have a separate endpoint for the MCP server. The current proposal is to keep the endpoint as it is, but it would be nice to have a simpler endpoint or even double it and deprecate the old one. No newline at end of file |
There was a problem hiding this comment.
I also noticed the same inconsistency and left a similar related comment elsewhere.
TLDR: I don't see, yet, a need to have a different endpoint (as in the Phoenix.Endpoint meaning) for the embedded mcp server. It could very well be a route in the current endpoint.
Unless I am missing something.
Description
RFC to describe the actions required to implement the MCP server as a web server instead of an external go application.
Fixes #
Reduces complexity of the implementation and test of the MCP server, reducing duplicated code.
Documentation changes
Yes