Demo
The demo module is a complete MCP server, small enough to be read in one sitting, exercising every extension point.
mvn package -pl demo exec:exec
Then register http://localhost:8080/mcp
in a client - see Clients
.
The tools and the prompt it exposes - names, descriptions, parameters and schemas - are listed in the reference at the end of this page, generated from the module itself.
Source: demo/src/main/java/io/yupiik/fusion/mcp/demo/ - about 200 lines in three classes:
| Class | Extension point |
|---|---|
|
|
the |
|
|
|
|
|
|
A guided session
MCP=http://localhost:8080/mcp
SID=$(curl -si -X POST $MCP -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
"protocolVersion":"2025-06-18","capabilities":{"sampling":{}},
"clientInfo":{"name":"curl","version":"1"}}}' \
| grep -i mcp-session-id | tr -d '\r' | cut -d' ' -f2)
post() { curl -s -X POST $MCP -H 'content-type: application/json' -H "mcp-session-id: $SID" -d "$1"; }
post '{"jsonrpc":"2.0","method":"notifications/initialized"}'
# a tool, with its structured result
post '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"demo/greet","arguments":{"name":"fusion","times":3}}}'
# {"result":{"content":[{"text":"{\"something\":\"hello fusion!!!\"}","type":"text"}],
# "isError":false,"structuredContent":{"something":"hello fusion!!!"}}}
# a failure: readable by the model, not a protocol error
post '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"demo/greet","arguments":{"name":" "}}}'
# {"result":{"content":[{"text":"name should not be blank","type":"text"}],"isError":true, ...}}
# a prompt and the completion of its argument
post '{"jsonrpc":"2.0","id":4,"method":"prompts/get","params":{"name":"demo/prompt","arguments":{"code":"1234"}}}'
post '{"jsonrpc":"2.0","id":5,"method":"completion/complete","params":{
"ref":{"type":"ref/prompt","name":"demo/prompt"},"argument":{"name":"code","value":"f"}}}'
# {"result":{"completion":{"hasMore":false,"total":1,"values":["fusion"]}}}
# a templated resource
post '{"jsonrpc":"2.0","id":6,"method":"resources/read","params":{"uri":"demo://echo/hello"}}'
Watching the server talk back
Open the stream in one terminal:
curl -N $MCP -H 'accept: text/event-stream' -H "mcp-session-id: $SID"
and call the logging tool in another:
post '{"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"demo/log","arguments":{"message":"hello"}}}'
The stream shows the record:
id: 1
event: message
data: {"jsonrpc":"2.0","method":"notifications/message","params":{"data":"hello","level":"info","logger":"demo"}}
demo/ask goes one step further: it sends a sampling/createMessage request on that stream and waits for the client to post the answer back - the full round trip is scripted in DemoTest#sampling, see Testing
.
Native image
mvn package arthur:native-image -pl demo
./demo/target/fusion-mcp-server-demo.graal.bin
No configuration is needed beyond what Fusion generates: no reflection, no dynamic proxy, and the OpenRPC document the tool descriptors come from is registered as a resource by the processor.
Reference
Generated from demo/target/classes/META-INF/fusion/jsonrpc/openrpc.json, i.e. from the signatures themselves - it is the same document the server builds its tool descriptors from.
Methods
demo/ask
Parameter structure: either.
Asks the client model to answer a question.
-
question(string): The question to forward to the client model.
Result: Demo
demo/confirm
Parameter structure: either.
Asks the user to confirm an action.
-
action(string): What has to be confirmed.
Result: Demo
demo/greet
Parameter structure: either.
Greets someone by name.
-
name(string): Who to greet. -
times(integer): How many times to greet, defaults to 1.
Result: DemoResponse
demo/log
Parameter structure: either.
Sends a log record to the client over the SSE channel.
-
message(string): What to log.
Result: Demo
demo/prompt
Parameter structure: either.
Demo.
-
code(string): The code to inject in the prompt.
Result: PromptResponse
demo/roots
Parameter structure: either.
Lists the workspace roots the client exposes.
This method does not have any parameter.
Result: DemoResponse
demo/search
Parameter structure: either.
Searches the demo catalog.
-
query(Query): The query. -
tags(array with items of typestring): Tags to filter on. -
options(object): Extra options. -
limit(integer): How many results at most. -
direction(enum with potential valuesasc,desc): Sort direction.
Result: DemoResponse
demo/tool
Schemas
Query (io.yupiik.fusion.mcp.demo.DemoTools.Query) schema
| Name | Type | Nullable | Description |
|---|---|---|---|
|
|
|
|
Should approximate matches be returned too. |
|
|
|
|
The text to search for, mandatory. |
Demo (io.yupiik.fusion.mcp.demo.model.Demo) schema
| Name | Type | Nullable | Description |
|---|---|---|---|
|
|
|
|
The greeting sentence, ready to be shown to the user. |
DemoResponse (io.yupiik.fusion.mcp.demo.model.DemoResponse) schema
| Name | Type | Nullable | Description |
|---|---|---|---|
|
|
|
|
What the tool has to say, a plain sentence. |
Metadata (io.yupiik.fusion.mcp.model.Metadata) schema
| Name | Type | Nullable | Description |
|---|---|---|---|
|
|
|
|
Reserved name attribute. |
|
|
object |
|
Every other attribute, this object being free form. |
|
|
|
|
Reserved title attribute. |
PromptResponse (io.yupiik.fusion.mcp.model.PromptResponse) schema
| Name | Type | Nullable | Description |
|---|---|---|---|
|
|
object of type |
|
Optional free form metadata. |
|
|
|
|
What the expanded prompt is about. |
|
|
array with items of type object of type |
|
The messages the prompt expands to. |
|
|
enum with potential values |
|
The type of this result, see the {@code 2026-07-28} specification. |
Message (io.yupiik.fusion.mcp.model.PromptResponse.Message) schema
| Name | Type | Nullable | Description |
|---|---|---|---|
|
|
object |
|
The message content, a single block or an array of blocks. |
|
|
|
|
Who the message comes from. |