Skip to content

Commit e083d9d

Browse files
author
rainu
committed
add possibility to start the mcp-server as a streamable http-server
1 parent 2489037 commit e083d9d

File tree

4 files changed

+130
-6
lines changed

4 files changed

+130
-6
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ Or you can rename the binary to `ask-mai-mcp-server` and start it like this:
145145
ask-mai-mcp-server
146146
```
147147

148+
Do run the MCP server as a streamable HTTP server, you can use the `-http-address` flag:
149+
```bash
150+
ask-mai ask-mai-mcp-server --http-address=":8080"
151+
```
152+
148153
## How to build this application
149154

150155
1. Install dependencies [see wails documentation](https://wails.io/docs/gettingstarted/installation)

frontend/wailsjs/go/models.ts

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2221,9 +2221,24 @@ export namespace llm {
22212221

22222222
export namespace mcp {
22232223

2224+
export class Meta {
2225+
ProgressToken: any;
2226+
AdditionalFields: Record<string, any>;
2227+
2228+
static createFrom(source: any = {}) {
2229+
return new Meta(source);
2230+
}
2231+
2232+
constructor(source: any = {}) {
2233+
if ('string' === typeof source) source = JSON.parse(source);
2234+
this.ProgressToken = source["ProgressToken"];
2235+
this.AdditionalFields = source["AdditionalFields"];
2236+
}
2237+
}
22242238
export class Annotations {
22252239
audience?: string[];
22262240
priority?: number;
2241+
lastModified?: string;
22272242

22282243
static createFrom(source: any = {}) {
22292244
return new Annotations(source);
@@ -2233,11 +2248,13 @@ export namespace mcp {
22332248
if ('string' === typeof source) source = JSON.parse(source);
22342249
this.audience = source["audience"];
22352250
this.priority = source["priority"];
2251+
this.lastModified = source["lastModified"];
22362252
}
22372253
}
22382254
export class AudioContent {
22392255
// Go type: Annotations
22402256
annotations?: any;
2257+
_meta?: Meta;
22412258
type: string;
22422259
data: string;
22432260
mimeType: string;
@@ -2249,6 +2266,7 @@ export namespace mcp {
22492266
constructor(source: any = {}) {
22502267
if ('string' === typeof source) source = JSON.parse(source);
22512268
this.annotations = this.convertValues(source["annotations"], null);
2269+
this._meta = this.convertValues(source["_meta"], Meta);
22522270
this.type = source["type"];
22532271
this.data = source["data"];
22542272
this.mimeType = source["mimeType"];
@@ -2273,8 +2291,9 @@ export namespace mcp {
22732291
}
22742292
}
22752293
export class CallToolResult {
2276-
_meta?: Record<string, any>;
2294+
_meta?: Meta;
22772295
content: any[];
2296+
structuredContent?: any;
22782297
isError?: boolean;
22792298

22802299
static createFrom(source: any = {}) {
@@ -2283,14 +2302,34 @@ export namespace mcp {
22832302

22842303
constructor(source: any = {}) {
22852304
if ('string' === typeof source) source = JSON.parse(source);
2286-
this._meta = source["_meta"];
2305+
this._meta = this.convertValues(source["_meta"], Meta);
22872306
this.content = source["content"];
2307+
this.structuredContent = source["structuredContent"];
22882308
this.isError = source["isError"];
22892309
}
2310+
2311+
convertValues(a: any, classs: any, asMap: boolean = false): any {
2312+
if (!a) {
2313+
return a;
2314+
}
2315+
if (a.slice && a.map) {
2316+
return (a as any[]).map(elem => this.convertValues(elem, classs));
2317+
} else if ("object" === typeof a) {
2318+
if (asMap) {
2319+
for (const key of Object.keys(a)) {
2320+
a[key] = new classs(a[key]);
2321+
}
2322+
return a;
2323+
}
2324+
return new classs(a);
2325+
}
2326+
return a;
2327+
}
22902328
}
22912329
export class EmbeddedResource {
22922330
// Go type: Annotations
22932331
annotations?: any;
2332+
_meta?: Meta;
22942333
type: string;
22952334
resource: any;
22962335

@@ -2301,6 +2340,7 @@ export namespace mcp {
23012340
constructor(source: any = {}) {
23022341
if ('string' === typeof source) source = JSON.parse(source);
23032342
this.annotations = this.convertValues(source["annotations"], null);
2343+
this._meta = this.convertValues(source["_meta"], Meta);
23042344
this.type = source["type"];
23052345
this.resource = source["resource"];
23062346
}
@@ -2323,9 +2363,26 @@ export namespace mcp {
23232363
return a;
23242364
}
23252365
}
2366+
export class Icon {
2367+
src: string;
2368+
mimeType?: string;
2369+
sizes?: string[];
2370+
2371+
static createFrom(source: any = {}) {
2372+
return new Icon(source);
2373+
}
2374+
2375+
constructor(source: any = {}) {
2376+
if ('string' === typeof source) source = JSON.parse(source);
2377+
this.src = source["src"];
2378+
this.mimeType = source["mimeType"];
2379+
this.sizes = source["sizes"];
2380+
}
2381+
}
23262382
export class ImageContent {
23272383
// Go type: Annotations
23282384
annotations?: any;
2385+
_meta?: Meta;
23292386
type: string;
23302387
data: string;
23312388
mimeType: string;
@@ -2337,6 +2394,7 @@ export namespace mcp {
23372394
constructor(source: any = {}) {
23382395
if ('string' === typeof source) source = JSON.parse(source);
23392396
this.annotations = this.convertValues(source["annotations"], null);
2397+
this._meta = this.convertValues(source["_meta"], Meta);
23402398
this.type = source["type"];
23412399
this.data = source["data"];
23422400
this.mimeType = source["mimeType"];
@@ -2360,6 +2418,7 @@ export namespace mcp {
23602418
return a;
23612419
}
23622420
}
2421+
23632422
export class Timeout {
23642423
Init?: number;
23652424
List?: number;
@@ -2423,6 +2482,7 @@ export namespace mcp {
24232482
export class TextContent {
24242483
// Go type: Annotations
24252484
annotations?: any;
2485+
_meta?: Meta;
24262486
type: string;
24272487
text: string;
24282488

@@ -2433,6 +2493,7 @@ export namespace mcp {
24332493
constructor(source: any = {}) {
24342494
if ('string' === typeof source) source = JSON.parse(source);
24352495
this.annotations = this.convertValues(source["annotations"], null);
2496+
this._meta = this.convertValues(source["_meta"], Meta);
24362497
this.type = source["type"];
24372498
this.text = source["text"];
24382499
}
@@ -2456,6 +2517,18 @@ export namespace mcp {
24562517
}
24572518
}
24582519

2520+
export class ToolExecution {
2521+
taskSupport?: string;
2522+
2523+
static createFrom(source: any = {}) {
2524+
return new ToolExecution(source);
2525+
}
2526+
2527+
constructor(source: any = {}) {
2528+
if ('string' === typeof source) source = JSON.parse(source);
2529+
this.taskSupport = source["taskSupport"];
2530+
}
2531+
}
24592532
export class ToolAnnotation {
24602533
title?: string;
24612534
readOnlyHint?: boolean;
@@ -2476,38 +2549,72 @@ export namespace mcp {
24762549
this.openWorldHint = source["openWorldHint"];
24772550
}
24782551
}
2552+
export class ToolOutputSchema {
2553+
$defs?: Record<string, any>;
2554+
type: string;
2555+
properties?: Record<string, any>;
2556+
required?: string[];
2557+
additionalProperties?: any;
2558+
2559+
static createFrom(source: any = {}) {
2560+
return new ToolOutputSchema(source);
2561+
}
2562+
2563+
constructor(source: any = {}) {
2564+
if ('string' === typeof source) source = JSON.parse(source);
2565+
this.$defs = source["$defs"];
2566+
this.type = source["type"];
2567+
this.properties = source["properties"];
2568+
this.required = source["required"];
2569+
this.additionalProperties = source["additionalProperties"];
2570+
}
2571+
}
24792572
export class ToolInputSchema {
2573+
$defs?: Record<string, any>;
24802574
type: string;
24812575
properties?: Record<string, any>;
24822576
required?: string[];
2577+
additionalProperties?: any;
24832578

24842579
static createFrom(source: any = {}) {
24852580
return new ToolInputSchema(source);
24862581
}
24872582

24882583
constructor(source: any = {}) {
24892584
if ('string' === typeof source) source = JSON.parse(source);
2585+
this.$defs = source["$defs"];
24902586
this.type = source["type"];
24912587
this.properties = source["properties"];
24922588
this.required = source["required"];
2589+
this.additionalProperties = source["additionalProperties"];
24932590
}
24942591
}
24952592
export class Tool {
2593+
_meta?: Meta;
24962594
name: string;
24972595
description?: string;
24982596
inputSchema: ToolInputSchema;
2597+
outputSchema?: ToolOutputSchema;
24992598
annotations: ToolAnnotation;
2599+
defer_loading?: boolean;
2600+
icons?: Icon[];
2601+
execution?: ToolExecution;
25002602

25012603
static createFrom(source: any = {}) {
25022604
return new Tool(source);
25032605
}
25042606

25052607
constructor(source: any = {}) {
25062608
if ('string' === typeof source) source = JSON.parse(source);
2609+
this._meta = this.convertValues(source["_meta"], Meta);
25072610
this.name = source["name"];
25082611
this.description = source["description"];
25092612
this.inputSchema = this.convertValues(source["inputSchema"], ToolInputSchema);
2613+
this.outputSchema = this.convertValues(source["outputSchema"], ToolOutputSchema);
25102614
this.annotations = this.convertValues(source["annotations"], ToolAnnotation);
2615+
this.defer_loading = source["defer_loading"];
2616+
this.icons = this.convertValues(source["icons"], Icon);
2617+
this.execution = this.convertValues(source["execution"], ToolExecution);
25112618
}
25122619

25132620
convertValues(a: any, classs: any, asMap: boolean = false): any {
@@ -2529,6 +2636,8 @@ export namespace mcp {
25292636
}
25302637
}
25312638

2639+
2640+
25322641

25332642
}
25342643

@@ -2970,6 +3079,7 @@ export namespace model {
29703079
Profiles: Record<string, Profile>;
29713080
Themes: Themes;
29723081
Version: boolean;
3082+
HttpAddress: string;
29733083
Help: Help;
29743084

29753085
static createFrom(source: any = {}) {
@@ -2985,6 +3095,7 @@ export namespace model {
29853095
this.Profiles = this.convertValues(source["Profiles"], Profile, true);
29863096
this.Themes = this.convertValues(source["Themes"], Themes);
29873097
this.Version = source["Version"];
3098+
this.HttpAddress = source["HttpAddress"];
29883099
this.Help = this.convertValues(source["Help"], Help);
29893100
}
29903101

internal/app/mcp-server/main.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ package mcp_server
22

33
import (
44
"fmt"
5+
"log/slog"
6+
"os"
7+
58
"github.com/mark3labs/mcp-go/server"
69
"github.com/rainu/ask-mai/internal/config"
710
mcpServer "github.com/rainu/ask-mai/internal/mcp/server"
8-
"log/slog"
9-
"os"
1011
)
1112

1213
type Args struct {
@@ -29,7 +30,13 @@ func Main(args Args) int {
2930
ap := cfg.GetActiveProfile()
3031

3132
ms := mcpServer.NewServer(args.VersionLine, ap.LLM.Tool.BuiltIns, ap.LLM.Tool.Custom)
32-
err := server.ServeStdio(ms)
33+
34+
var err error
35+
if cfg.HttpAddress != "" {
36+
err = server.NewStreamableHTTPServer(ms).Start(cfg.HttpAddress)
37+
} else {
38+
err = server.ServeStdio(ms)
39+
}
3340

3441
if err != nil {
3542
fmt.Fprintln(os.Stderr, err.Error())

internal/config/model/general.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ type Config struct {
1414
Profiles map[string]*Profile `yaml:"profiles,omitempty" usage:"Configuration profiles. Each profile has the same structure as the main configuration: "`
1515
Themes Themes `yaml:"themes,omitempty" usage:"Theme settings for the application: "`
1616

17-
Version bool `yaml:"version,omitempty" short:"v" usage:"Show the version"`
17+
Version bool `yaml:"version,omitempty" short:"v" usage:"Show the version"`
18+
HttpAddress string `yaml:"http-address,omitempty" usage:"Address to listen on for MCP-HTTP server (e.g. \":8080\"). If not set, the server will run in stdio mode."`
1819

1920
Help Help `yaml:",inline,omitempty"`
2021
}

0 commit comments

Comments
 (0)