Rationale
It is now expected that application exposes an MCP server to be operated from a LLM.
Proposal
As the protocol is based on JSON-RPC, it could fit easily in the Tryton stack.
We can use the user application to enforce the access rights.
We add a specialized Router for MCP which applies a user_application('mcp') to all its route.
Here is a syntax example:
class Capability:
read_access: list[str]
create_access: list[str]
write_access: list[str]
delete_access: list[str]
...
class Tool(Capability):
...
class Resource(Capability):
...
class Prompt(Capability):
...
mcp_application = user_application('mcp')
class MCP(Router):
@classmethod
def __setup__(cls):
super().__setup__()
cls.__routes__.update({
'mcp': Route(
'/<database_name>/mcp', methods={'POST'},
decorators=[
with_pool,
with_transaction(),
mcp_application,
],
),
})
cls.tools = {
'search_users': Tool(
'title': "Search users",
'description': "Search users in the database...",
'read_access': ['res.user'],
),
}
cls.resources = {
'get_user_profile': Resource('users://{id}/profile'),
}
cls.prompts = {
'get_user_name': Prompt(),
}
@classmethod
def mcp(cls, request, pool):
...
@classmethod
def search_user(cls, query: Annotated[str, Description("username to search for")], limit: int = 10, administrator: bool= false) -> list[str]:
...
@classmethod
def get_user_profile(cls, id: str) -> str:
...
return f"User {user.name}"
@classmethod
def get_user_name(cls, login: str) -> str:
return f"Please fetch the user name with the login {login}"
The mcp method handle the requests by dispatching the request, enforcing the access rights and input types and formatting the answer.
It uses the annotation types of the method to generate the definitions.
This API was inspired by mcp.