Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
d718e1c
build(deps): bump github.com/blevesearch/bleve_index_api
dependabot[bot] Mar 20, 2026
930e541
Merge branch 'develop' into dependabot/go_modules/develop/github.com/…
marle3003 Mar 21, 2026
2c6649c
Merge pull request #887 from marle3003/dependabot/go_modules/develop/…
github-actions[bot] Mar 21, 2026
0a02725
feat(javascript): add insecure option to http request methods
marle3003 Mar 23, 2026
32536d4
Merge remote-tracking branch 'origin/develop' into develop
marle3003 Mar 23, 2026
e80532c
feat(webui): prevent null reference error
marle3003 Mar 24, 2026
ce206fc
fix(config): improve config files without a file extension
marle3003 Mar 24, 2026
8f0851b
fix(webui): improve displaying header controls in source view component
marle3003 Mar 24, 2026
ff98f63
test(imap): improve test
marle3003 Mar 24, 2026
7ab4951
fix(json parser): use Exportable interface when schema or property is…
marle3003 Mar 25, 2026
3d1b7bb
build(deps): bump github.com/blevesearch/bleve_index_api
dependabot[bot] Mar 27, 2026
de4a8d8
Merge pull request #897 from marle3003/dependabot/go_modules/develop/…
github-actions[bot] Mar 27, 2026
1c2abde
style(webui): hide column if number of content types is not one
marle3003 Mar 27, 2026
2c48d77
Merge remote-tracking branch 'origin/develop' into develop
marle3003 Mar 27, 2026
44e92cc
chore(webui): improve bundle size
marle3003 Mar 27, 2026
b8faf84
build(deps): bump nodemailer from 8.0.2 to 8.0.4 in /webui
dependabot[bot] Mar 27, 2026
ee14479
chore(webui): improve bundle size
marle3003 Mar 27, 2026
569e98d
feat(mcp): add MCP server
marle3003 Mar 29, 2026
3667927
fix(http): nil reference in drain request body
marle3003 Mar 29, 2026
5a1019a
feat(mcp): add get_mokapi_js_api tool
marle3003 Mar 30, 2026
67a5a4a
fix(javascript): fix concurrent map access in shared values
marle3003 Mar 30, 2026
e566800
feat(mcp): add tools get_http_response_schema and generate_http_response
marle3003 Mar 31, 2026
49c1581
fix(generator): fix generate date around New Year's Eve
marle3003 Mar 31, 2026
50e9e5a
feat(mcp): update and extend tools
marle3003 Mar 31, 2026
d22f518
chore: update gitignore
marle3003 Mar 31, 2026
5dcae15
chore: update gitignore
marle3003 Mar 31, 2026
bc83d9e
Clean DS_Store files
marle3003 Mar 31, 2026
604ba4d
chore: remove unwanted commits
marle3003 Mar 31, 2026
c601dca
Merge remote-tracking branch 'origin/develop' into develop
marle3003 Mar 31, 2026
5fefb13
Remove macOS Icon file
marle3003 Mar 31, 2026
613ab98
feat(mcp): improve tools collection
marle3003 Mar 31, 2026
6d21772
Merge branch 'develop' into dependabot/npm_and_yarn/webui/develop/nod…
marle3003 Apr 1, 2026
6b63c54
Merge pull request #902 from marle3003/dependabot/npm_and_yarn/webui/…
github-actions[bot] Apr 1, 2026
9af4488
build(deps): bump xml-formatter from 3.6.7 to 3.7.0 in /webui
dependabot[bot] Apr 1, 2026
4ae1c24
Merge pull request #899 from marle3003/dependabot/npm_and_yarn/webui/…
github-actions[bot] Apr 1, 2026
644c671
build(deps-dev): bump eslint from 10.0.3 to 10.1.0 in /webui
dependabot[bot] Apr 1, 2026
9a98cba
Merge pull request #900 from marle3003/dependabot/npm_and_yarn/webui/…
github-actions[bot] Apr 1, 2026
b459711
build(deps-dev): bump @vue/tsconfig from 0.9.0 to 0.9.1 in /webui
dependabot[bot] Apr 1, 2026
13d7bb8
Merge pull request #898 from marle3003/dependabot/npm_and_yarn/webui/…
github-actions[bot] Apr 1, 2026
7804dd9
build(deps-dev): bump @vitejs/plugin-vue from 6.0.4 to 6.0.5 in /webui
dependabot[bot] Apr 1, 2026
ac60bd9
Merge pull request #901 from marle3003/dependabot/npm_and_yarn/webui/…
github-actions[bot] Apr 1, 2026
d14d18e
feat(mcp): improve tools collection
marle3003 Apr 1, 2026
51b5d94
Merge remote-tracking branch 'origin/develop' into develop
marle3003 Apr 1, 2026
c2bd0de
chore(context7): claim library
marle3003 Apr 1, 2026
5dbab5e
Merge branch 'main' into develop
marle3003 Apr 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ node_modules
server/api/dashboard.go
coverage.txt
versioninfo.json
.DS_Store
Icon
1,284 changes: 644 additions & 640 deletions .idea/workspace.xml

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions api/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
type Handler interface {
http.Handler
RegisterHealthHandler(path string, h http.Handler)
RegisterMcpHandler(path string, h http.Handler)
}

type handler struct {
Expand All @@ -33,6 +34,8 @@ type handler struct {
index string
healthPath string
healthHandler http.Handler
mcpPath string
mcpHandler http.Handler
}

type info struct {
Expand Down Expand Up @@ -111,6 +114,11 @@ func (h *handler) RegisterHealthHandler(path string, handler http.Handler) {
h.healthHandler = handler
}

func (h *handler) RegisterMcpHandler(path string, handler http.Handler) {
h.mcpPath = path
h.mcpHandler = handler
}

func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" && r.Method != "POST" {
http.Error(w, fmt.Sprintf("method %v is not allowed", r.Method), http.StatusMethodNotAllowed)
Expand Down Expand Up @@ -154,6 +162,8 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.getSearchResults(w, r)
case strings.HasPrefix(p, h.healthPath) && h.healthHandler != nil:
h.healthHandler.ServeHTTP(w, r)
case strings.HasPrefix(p, h.mcpPath) && h.mcpHandler != nil:
h.mcpHandler.ServeHTTP(w, r)
case h.fileServer != nil:
if r.Method != "GET" {
http.Error(w, fmt.Sprintf("method %v is not allowed", r.Method), http.StatusMethodNotAllowed)
Expand Down
12 changes: 11 additions & 1 deletion api/handler_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,17 @@ func (h *handler) getConfigData(w http.ResponseWriter, r *http.Request, key stri
ext := filepath.Ext(path)
mt := mime.TypeByExtension(filepath.Ext(ext))
if mt == "" {
mt = "text/plain"
if ext == "" {
values, err := mime.ExtensionsByType(c.Info.Kernel().ContentType)
if err == nil && len(values) > 0 {
ext = values[0]
path += ext
mt = mime.TypeByExtension(filepath.Ext(ext))
}
}
if mt == "" {
mt = "text/plain"
}
}
w.Header().Set("Last-Modified", c.Info.Time.UTC().Format(http.TimeFormat))
w.Header().Set("Content-Type", mt)
Expand Down
29 changes: 29 additions & 0 deletions api/handler_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ func TestHandler_Config(t *testing.T) {
requestUrl: "http://foo.api/api/configs/foo/data",
test: []try.ResponseCondition{
try.HasStatusCode(http.StatusOK),
try.HasHeader("Content-Disposition", "inline; filename=\"foo.yaml\""),
try.HasHeader("Last-Modified", "Wed, 27 Dec 2023 13:01:30 GMT"),
try.HasHeaderXor("Content-Type", "text/plain", "application/yaml"),
try.HasHeader("Cache-Control", "no-cache"),
Expand All @@ -173,6 +174,34 @@ func TestHandler_Config(t *testing.T) {
requestUrl: "http://foo.api/api/configs/foo/data",
test: []try.ResponseCondition{
try.HasStatusCode(http.StatusOK),
try.HasHeader("Content-Disposition", "inline; filename=\"foo.json\""),
try.HasHeader("Last-Modified", "Fri, 22 Dec 2023 13:01:30 GMT"),
try.HasHeader("Content-Type", "application/json"),
try.HasHeader("Etag", etag),
try.HasHeader("Cache-Control", "no-cache"),
try.HasBody(`{"foo": "bar"}`),
},
},
{
name: "config data: no extension but ContentType in Info is set",
app: func() *runtime.App {

return &runtime.App{Configs: map[string]*dynamic.Config{
"foo": {
Info: dynamic.ConfigInfo{
Url: mustUrl("https://foo.bar/foo"),
Time: mustTime("2023-12-22T13:01:30+00:00"),
Checksum: checksum,
ContentType: "application/json",
},
Raw: data,
},
}}
},
requestUrl: "http://foo.api/api/configs/foo/data",
test: []try.ResponseCondition{
try.HasStatusCode(http.StatusOK),
try.HasHeader("Content-Disposition", "inline; filename=\"foo.json\""),
try.HasHeader("Last-Modified", "Fri, 22 Dec 2023 13:01:30 GMT"),
try.HasHeader("Content-Type", "application/json"),
try.HasHeader("Etag", etag),
Expand Down
5 changes: 5 additions & 0 deletions cmd/mokapi/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ health:
path: /health
port: 8080
log: false
mcp:
server:
enabled: false
path: /mcp
port: 8080
rootCaCert: ""
rootCaKey: ""
configs: []
Expand Down
13 changes: 7 additions & 6 deletions config/dynamic/config_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ import (
)

type ConfigInfo struct {
Provider string
Url *url.URL
Checksum []byte
Time time.Time
inner *ConfigInfo
Tags []string
Provider string
Url *url.URL
Checksum []byte
Time time.Time
inner *ConfigInfo
Tags []string
ContentType string
}

func (ci *ConfigInfo) Path() string {
Expand Down
2 changes: 2 additions & 0 deletions config/dynamic/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,12 @@ func parse(c *Config) (interface{}, error) {
var v interface{}
v, err = parseJson(b, result)
if err == nil {
c.Info.ContentType = "application/json"
return v, nil
}
v, err = parseYaml(b, result)
if v != nil && err == nil {
c.Info.ContentType = "application/yaml"
return v, nil
}
err = nil
Expand Down
2 changes: 2 additions & 0 deletions config/dynamic/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ func TestParse(t *testing.T) {
err := dynamic.Parse(c, &dynamictest.Reader{})
require.NoError(t, err)
require.Equal(t, "foo", c.Data.(*data).User)
require.Equal(t, "application/json", c.Info.ContentType)
},
},
{
Expand Down Expand Up @@ -161,6 +162,7 @@ func TestParse(t *testing.T) {
err := dynamic.Parse(c, &dynamictest.Reader{})
require.NoError(t, err)
require.Equal(t, "foo", c.Data.(*data).User)
require.Equal(t, "application/yaml", c.Info.ContentType)
},
},
{
Expand Down
4 changes: 4 additions & 0 deletions config/dynamic/provider/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ func (p *Provider) readUrl(u *url.URL) (c *dynamic.Config, changed bool, err err
Raw: b,
}

if ct := res.Header.Get("Content-Type"); ct != "" {
c.Info.ContentType = ct
}

return
}

Expand Down
29 changes: 26 additions & 3 deletions config/dynamic/provider/http/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ package http
import (
"context"
"fmt"
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/require"
"io"
"mokapi/config/dynamic"
"mokapi/config/static"
Expand All @@ -15,6 +12,10 @@ import (
"net/http/httptest"
"testing"
"time"

"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/require"
)

func TestProvider_Start(t *testing.T) {
Expand Down Expand Up @@ -159,6 +160,28 @@ func TestProvider_Start(t *testing.T) {
require.Equal(t, fmt.Sprintf("request to %v failed: request has timed out", url), hook.LastEntry().Message)
},
},
{
name: "content type",
init: func() (static.HttpProvider, *httptest.Server) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("foo: bar"))
}))

cfg := static.HttpProvider{
Urls: []string{server.URL},
}

return cfg, server
},
test: func(t *testing.T, url string, ch chan dynamic.ConfigEvent, hook *test.Hook, err error) {
require.NoError(t, err)
c := <-ch
require.Equal(t, "foo: bar", string(c.Config.Raw))
require.Equal(t, "application/json", c.Config.Info.ContentType)
},
},
}

for _, tc := range testcases {
Expand Down
19 changes: 19 additions & 0 deletions config/static/static_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type Config struct {
Providers Providers `json:"providers" yaml:"providers"`
Api Api `json:"api" yaml:"api"`
Health Health `json:"health" yaml:"health"`
Mcp Mcp `json:"mcp" yaml:"mcp"`
RootCaCert tls.FileOrContent `json:"rootCaCert" yaml:"rootCaCert" name:"root-ca-cert"`
RootCaKey tls.FileOrContent `json:"rootCaKey" yaml:"rootCaKey" name:"root-ca-cert"`
Configs Configs `json:"configs" yaml:"configs" explode:"config"`
Expand All @@ -44,6 +45,14 @@ func NewConfig() *Config {
cfg.Health.Port = 8080
cfg.Health.Path = "/health"

cfg.Mcp = Mcp{
Server: McpServer{
Enabled: false,
Port: 8080,
Path: "/mcp",
},
}

cfg.Providers.File.SkipPrefix = []string{"_"}
cfg.Event.Store = map[string]Store{"default": {Size: 100}}
cfg.DataGen.OptionalProperties = "0.85"
Expand Down Expand Up @@ -298,3 +307,13 @@ type Health struct {
Port int `yaml:"port" json:"port"`
Log bool `yaml:"log" json:"log"`
}

type Mcp struct {
Server McpServer `yaml:"server" json:"server"`
}

type McpServer struct {
Enabled bool `yaml:"enabled" json:"enabled"`
Path string `yaml:"path" json:"path"`
Port int `yaml:"port" json:"port"`
}
4 changes: 4 additions & 0 deletions context7.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"url": "https://context7.com/marle3003/mokapi",
"public_key": "pk_aZSdHtCTd5H3Tm72PzeNI"
}
15 changes: 8 additions & 7 deletions docs/javascript-api/mokapi-http/fetchoptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ description: The FetchOptions object defines parameters for the fetch() function
The `FetchOptions` object defines additional parameters for the [`fetch()`](/docs/javascript-api/mokapi-http/fetch.md) function in the `mokapi/http` module.
It allows you to customize request behavior such as HTTP method, headers, body, timeout, and redirect handling.

| Name | Type | Description |
|--------------|----------------|--------------------------------------------------------------------------------------------------------------|
| method | string | The HTTP method used for the request (e.g. `"GET"`, `"POST"`, `"PUT"`). Defaults to `"GET"`. | |
| body | object | The request body to send. Automatically serialized to JSON when `Content-Type` is set to `application/json`. |
| headers | object | Key-value pairs representing HTTP headers to include with the request. |
| maxRedirects | number | The number of redirects to follow. Default value is 5. A value of 0 (zero) prevents all redirection. |
| timeout | number, string | Maximum time to wait for the request to complete. Default timeout is 60 seconds ("60s") |
| Name | Type | Description |
|--------------|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
| method | string | The HTTP method used for the request (e.g. `"GET"`, `"POST"`, `"PUT"`). Defaults to `"GET"`. | |
| body | any | The request body to send. Automatically serialized to JSON when `Content-Type` is set to `application/json`. |
| headers | object | Key-value pairs representing HTTP headers to include with the request. |
| maxRedirects | number | The number of redirects to follow. Default value is 5. A value of 0 (zero) prevents all redirection. |
| timeout | number, string | Maximum time to wait for the request to complete. Default timeout is 60 seconds ("60s") |
| insecure | boolean | If set to true, TLS certificate verification is skipped. This allows connections to servers with self-signed or invalid certificates. Default is false. |

## Example of Accept header

Expand Down
2 changes: 1 addition & 1 deletion docs/javascript-api/mokapi-kafka/produceargs.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ProduceArgs is an object used by [produce](/docs/javascript-api/mokapi-kafka/pro
|-----------------------------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| cluster (optional) | string | Kafka cluster name. Used when topic name is not unique. |
| topic (optional) | string | Kafka topic name. If not specified, message will be written to a random topic. |
| messages | array | An list of [Message](/docs/javascript-api/mokapi-kafka/message.md) contains Kafka messages to produce into given topic |
| messages | array | A list of [Message](/docs/javascript-api/mokapi-kafka/message.md) contains Kafka messages to produce into given topic |
| partition (optional, deprecated ) | number | Kafka partition index. If not specified, the message will be written to any partition |
| key (optional, deprecated) | any | Kafka message key. If not specified, a random key will be generated based on the topic configuration. |
| value (optional, deprecated) | any | Kafka message value. If not specified, a random value will be generated based on the topic configuration. Object will be encoded based on the topic configuration |
Expand Down
12 changes: 6 additions & 6 deletions docs/javascript-api/mokapi/eventhandler/kafkaeventmessage.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ description: KafkaEventMessage is an object used by KafkaEventHandler
KafkaMessage is an object used by [KafkaEventHandler](/docs/javascript-api/mokapi/eventhandler/kafkaeventhandler.md)
that contains Kafka-specific message data.

| Name | Type | Description |
|---------|--------|---------------------------------------------------------------|
| offset | number | Kafka partition where the message was written to (read-only). |
| key | string | Kafka message key |
| value | string | Kafka message value |
| headers | object | Kafka message headers |
| Name | Type | Description |
|---------|--------|------------------------------------------------|
| offset | number | Kafka offset of the kafka message (read-only). |
| key | string | Kafka message key |
| value | string | Kafka message value |
| headers | object | Kafka message headers |

1 change: 1 addition & 0 deletions engine/common/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ type HttpClient interface {
type HttpClientOptions struct {
MaxRedirects int
Timeout time.Duration
Insecure bool
}

type Action struct {
Expand Down
14 changes: 12 additions & 2 deletions engine/host.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package engine

import (
"crypto/tls"
"encoding/json"
"fmt"
"mokapi/config/dynamic"
Expand Down Expand Up @@ -283,8 +284,15 @@ func (sh *scriptHost) KafkaClient() common.KafkaClient {
}

func (sh *scriptHost) HttpClient(opts common.HttpClientOptions) common.HttpClient {
return &http.Client{
Timeout: opts.Timeout,
transport := http.DefaultTransport.(*http.Transport).Clone()

if opts.Insecure {
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}

c := &http.Client{
Transport: transport,
Timeout: opts.Timeout,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if l := len(via); l > opts.MaxRedirects {
log.Warnf("Stopped after %d redirects, original URL was %s", opts.MaxRedirects, via[0].URL)
Expand All @@ -293,6 +301,8 @@ func (sh *scriptHost) HttpClient(opts common.HttpClientOptions) common.HttpClien
return nil
},
}

return c
}

func (sh *scriptHost) CanClose() bool {
Expand Down
2 changes: 1 addition & 1 deletion examples/mokapi/services_http.js
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ export let apps = [
{
method: "get",
summary: "Finds Pets by status",
description: "Multiple status values can be provided with comma separated strings",
description: "Multiple status values **can** be provided with comma separated strings",
operationId: "findPetsByStatus",
tags: ["pet"],
parameters: [
Expand Down
Loading
Loading