Team leader of Scala Open Source Team
Coordinator and VirtusLab representative in Scala Core Team
Metals has the exact data to serve both purposes and makes it easier for people who already use it.
Model Context Protocol is very similar to Language Server Protocol, but instead of people it's for agents.
Host with MCP Client
MCP protocol
MCP protocol
MCP protocol
MCP Server 1
MCP Server 2
MCP Server 2
Local Data Source 1
Local Data Source 2
Web API
MCP uses Json RPC, so each possible request and definition is represented by json schema
Agents can ask the server for static content (resources) that might be useful for the current context
resources/list - list all available resource
resources/read - read specific resource
{
uri: string; // Unique identifier for the resource
name: string; // Human-readable name
description?: string; // Optional description
mimeType?: string; // Optional MIME type
}Example
{
uri: "file:///logs/app.log",
name: "Application Logs",
mimeType: "text/plain"
}Agents interact with external systems, perform computations, and take actions in the real world.
tools/list - list all the tools available on the server
tools/call - invoke the tool
{
name: string; // Unique identifier for the tool
description?: string; // Human-readable description
inputSchema: { // JSON Schema for the tool's parameters
type: "object",
properties: { ... } // Tool-specific parameters
},
annotations?: {} // Optional hints about tool behavior
}Example
{
"name" : "compile-file",
"description": "Compile a chosen Scala file",
"schema" : {
"type": "object",
"properties": {
"fileInFocus": {
"type": "string",
"description": "The file to compile..."
}
}
}
}- reusable prompt templates and workflows
- standardize and share common LLM interactions
- prompts/list and prompts/get requests
{
name: string; // Unique identifier for the prompt
description?: string; // Human-readable description
arguments?: [ // Optional list of arguments
{
name: string; // Argument identifier
description?: string; // Argument description
required?: boolean; // Whether argument is required
}
]
}
Example
{
name: "explain-code",
description: "Explain how code works",
arguments: [
{
name: "code",
description: "Code to explain",
required: true
},
{
name: "language",
description: "Programming language",
required: false
}
]
}
- Vs Code with Copilot
- Cursor
- Windsurf
- probably more!
To minimize amount of dependencies we use the default Java SDK - https://github.com/modelcontextprotocol/java-sdk
We start an additional HTTP server within Metals
compile-full: Compile the entire Scala project.
{
"name" : "compile-full",
"description": "Compile the whole Scala project",
"schema" : { "type": "object", "properties": {} }
}compile-file: Compile a specific file.
{
"name" : "compile-file",
"description": "Compile a chosen Scala file",
"schema" : {
"type": "object",
"properties": {
"fileInFocus": {
"type": "string",
"description": "The file to compile..."
}
}
}
}test: Run a Scala test suite.
{
"name" : "test",
"description": "Run Scala test suite",
"schema" : {
"type": "object",
"properties": {
"testFile": {
"type": "string",
"description": "The file containing the test suite, if empty we will try to detect it"
},
"testClass": {
"type": "string",
"description": "Fully qualified name of the test class to run"
},
"verbose": {
"type": "boolean",
"description": "Print all output from the test suite, otherwise prints only errors and summary",
"default": false
}
},
"required": ["testClass"]
}
}glob-search: Search for symbols using a glob pattern.
{
"name" : "glob-search",
"description": "Search for symbols using glob pattern",
"schema" : {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Substring of the symbol to search for"
},
"fileInFocus": {
"type": "string",
"description": "The current file in focus for context..."
}
},
"required": ["query"]
}
}typed-glob-search: Search for symbols by type.
{
"name" : "typed-glob-search",
"description": "Search for symbols by type using glob pattern",
"schema" : {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Substring of the symbol to search for"
},
"symbolType": {
"type": "array",
"items": {
"type": "string",
"enum": ["package", "class", "object", "function", "method", "trait"]
},
"description": "The type of symbol to search for"
},
"fileInFocus": {
"type": "string",
"description": "The current file in focus for context..."
}
},
"required": ["query", "symbolType"]
}
}inspect: Inspect a symbol for members, signatures...
{
"name" : "inspect",
"description": "Inspect a chosen Scala symbol.",
"schema" : {
"type": "object",
"properties": {
"fqcn": {
"type": "string",
"description": "Fully qualified name of the symbol to inspect"
},
"fileInFocus": {
"type": "string",
"description": "The current file in focus for context..."
}
},
"required": ["fqcn"]
}
}get-docs: Retrieve documentation for a symbol.
{
"name" : "get-docs",
"description": "Get documentation for a chosen Scala symbol",
"schema" : {
"type": "object",
"properties": {
"fqcn": {
"type": "string",
"description": "Fully qualified name of the symbol to get documentation for"
}
},
"required": ["fqcn"]
}
}get-usages: Find usages of a symbol.
{
"name" : "get-usages",
"description": "Get usages for a chosen Scala symbol.",
"schema" : {
"type": "object",
"properties": {
"fqcn": {
"type": "string",
"description": "Fully qualified name of the symbol to get usages for"
},
"fileInFocus": {
"type": "string",
"description": "The current file in focus for context..."
}
},
"required": ["fqcn"]
}
}import-build: Trigger a build import in the IDE.
{
"name" : "import-build",
"description": "Import the build to IDE",
"schema" : {"type": "object", "properties": {} }
}
We can add more! This is just the base idea.
Make sure you use newest Metals and enable the proper setting
Cursor and VS Code settings will be automatically set up for you
{
"metals.startMcpServer" : true
}Make sure that you use the Agent chat, this is the default in Cursor but not in VS Code
And you might sometimes need to force the agent to use MCP
This is still new so there is a lot of possible improvements
Their aim is to increase your productiveness
When suggesting code take into account cats documentation as primary inspiration:
Concepts
Cats Effect introduces a large number of concepts which,
while very general and individually simple, can seem
foreign and intimidating if you're new to the space.
This also brings along with it a set of terminology
for describing concepts and scenarios which can be
significantly different from that which is used in
other asynchronous frameworks (such as Akka or Vert.x).
This page is an attempt todescribe the Cats Effect
runtime at a high level, introducing the concepts and terminology which is
often assumed in discussions about the various details.
....find-dep: Coursier dependency resolution
{
"name" : "find-dep",
"description": "Use coursier to find a dependency",
"schema" : {
"type": "object",
"properties": {
"organization": {
"type": "string",
"description": "Organization to search for or its prefix"
},
"name": {
"type": "string",
"description": "Dependency name to search for or its prefix"
},
"version": {
"type": "string",
"description": "Version to search for or its prefix"
}
}
}
}run-diagnostics: Run diagnostics and debug metals
{
"name" : "run-diagnostics",
"description": "Access information about the current state of metals...",
"schema" : {"type": "object", "properties": {} }
}{
"name" : "buildTarget/sources",
"description": "Build target sources...",
"schema" : {
"type": "array",
"items": {
"type": "string",
}
}Automatically provide LSP / BSP methods as possible MCP tools.
Everything that you ask and LLM guesses wrong, we might be able to provide a tool to minimize those cases
You can write your own server!
There are some Scala MCP SDKs, you can use the to write things (or help out developing them)
There is even a prompt to help out https://modelcontextprotocol.io/llms-full.txt and copy the full documentation text
There is probably a lot to improve, though now when we improve metals we improve your mcp experience as well
It's quite experimental, try it out!