Tomasz Godzik
VirtusLab
Maintainer of multiple Scala tools including Metals, Bloop, Scalameta, Munit, Mdoc and parts of the Scala 3 compiler.
Maintainer of multiple Scala tools including Metals, Bloop, Scalameta, Munit, Mdoc and parts of the Scala 3 compiler.
Release officer for Scala LTS versions
Maintainer of multiple Scala tools including Metals, Bloop, Scalameta, Munit, Mdoc and parts of the Scala 3 compiler.
Release officer for Scala LTS versions
Part of the Scala Core team as coordinator and VirtusLab representative
Maintainer of multiple Scala tools including Metals, Bloop, Scalameta, Munit, Mdoc and parts of the Scala 3 compiler.
Release officer for Scala LTS versions
Part of the Scala Core team as coordinator and VirtusLab representative
Part of the moderation team
Model Context Protocol
what is it?
MCP & Scala
Executable MCP and skills
Questions
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 response 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
}
]
}
Metals has the exact data to serve both purposes and makes it easier for people who already use it.
And soon there will be default standalone MCP server for use outside Metals (Intellij!)
You can also build your own servers with Chimp, your own agents with sttp-ai
compile-full: Compile the entire Scala project. compile-module: Compile a single module compile-file: Compile current module and show errors from the current file
Most used by the agents, quick feedback loop and perfect for YOLO mode.
test: Run a Scala test suite or case
Often used, but my require additional direction for the agent
glob-search: Search for symbols using a glob pattern.
typed-glob-search: Search for symbols by type.
inspect: Inspect a symbol for members, signatures... get-docs: Retrieve documentation for a symbol
get-usages: Find usages of a symbol.
Rarely used, requires prompting the agent. A lot of the times replaced by grep even if the data is outside the workspace.
import-build: Trigger a build import in the IDE. format-file: Format given file, results applied directly find-dep: API to allow coursier complete-dep
Custom, mostly needs to be prompted or added in agent context
generate-scalafix-rule: ask metals to compile and run given generate scalafix rule
run-scalafix-rule: run existing or previously generated rule
list-scalafix-rules: list all existing and previously generated rules
Experimental, works only when user knows what they want.
But it's still useful to have that in your arsenal
servers
├── metals
│ ├── globSearch.scala
│ ├── getDocs.scala
│ ├── ... (other tools)
│ ├── clientUtils.scala
├── github
│ ├── issue.scala
│ ├── ... (other tools)
└── ... (other servers)// ./servers/metals/globSearch.scala
package metals.mcp
/* Potential pseudocode of a library with Ox */
def globSearch(
fullyQualifiedName: String,
target: Option[String]): String =
client.callTool("glob-search", fullyQualifiedName, target)
// ./skills/getDocsFor.scala
import metals.mcp.*
@main
def main(nameToLookFor: String) =
val allMatching = globSearch(fullyQualifiedName, None)
val fqcns = allMatching.split("\n")
val result = fqcns.map{
fullName => getDocs(fullName)
}.mkString("\n")
println(result)
}
You can think of it as your personal library of scripts that will also be available to the agents. And obviously you will be able to run them as well.
You can create skills based on session with and agent, so that next time you will get instant results.
---
name: get-docs-for-glob
description: Search for classes that satisfy this search parameters and...
---# Glob search
## Quick start
Run the script if you want to return users entire
documentation based on specific glob
(part of the name user is looking for)
```bash
scala-cli search-script.scala
```
glob-skill/
├── SKILL.md (main instructions)
├── REFERENCE.md (detailed API reference)
└── scripts/
└── globSearch.scala (utility script)---
name: your-skill-name
description: Brief description of what this Skill does and when to use it
---
# Your Skill Name
## Instructions
[Clear, step-by-step guidance for Claude to follow]
## Examples
[Concrete examples of using this Skill]there is some work needed to make it for Scala for more complex usage
Cursor generates a query that creates a new skill you might need.
Claude might also help, but you need to make sure the new file is created in .claude/skills
Bluesky: @tgodzik.bsky.social
Mastodon: fosstodon.org/@tgodzik
Discord: tgodzik