Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e14027b42 | ||
|
|
87cdcf28e0 | ||
|
|
441b181e79 |
No files matched your search
@@ -33,6 +33,7 @@ body:
|
|||||||
options:
|
options:
|
||||||
# The below comment is used to insert a new version with on-release.yml
|
# The below comment is used to insert a new version with on-release.yml
|
||||||
#NEXT_VERSION#
|
#NEXT_VERSION#
|
||||||
|
- 1.76.1
|
||||||
- 1.76.0
|
- 1.76.0
|
||||||
- 1.75.0
|
- 1.75.0
|
||||||
- 1.74.0
|
- 1.74.0
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { db } from "@homarr/db";
|
|||||||
|
|
||||||
import { getPackageVersion } from "~/versions/package-reader";
|
import { getPackageVersion } from "~/versions/package-reader";
|
||||||
import { extractMcpTools } from "../_extract-tools";
|
import { extractMcpTools } from "../_extract-tools";
|
||||||
|
import { serializeMcpToolResult } from "../_serialize-result";
|
||||||
|
|
||||||
const logger = createLogger({ module: "mcpRoute" });
|
const logger = createLogger({ module: "mcpRoute" });
|
||||||
|
|
||||||
@@ -203,7 +204,7 @@ const mcpHandler = createMcpHandler(
|
|||||||
const input = args && Object.keys(args).length > 0 ? args : undefined;
|
const input = args && Object.keys(args).length > 0 ? args : undefined;
|
||||||
const result = await procedure(input);
|
const result = await procedure(input);
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text" as const, text: JSON.stringify(result) }],
|
content: [{ type: "text" as const, text: serializeMcpToolResult(result) }],
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = sanitizeErrorMessage(error);
|
const message = sanitizeErrorMessage(error);
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { serializeMcpToolResult } from "./_serialize-result";
|
||||||
|
|
||||||
|
describe("serializeMcpToolResult", () => {
|
||||||
|
it("serializes objects as JSON strings", () => {
|
||||||
|
expect(serializeMcpToolResult({ boardId: "1" })).toBe('{"boardId":"1"}');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("serializes primitive values", () => {
|
||||||
|
expect(serializeMcpToolResult("hello")).toBe('"hello"');
|
||||||
|
expect(serializeMcpToolResult(42)).toBe("42");
|
||||||
|
expect(serializeMcpToolResult(true)).toBe("true");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("serializes null as the string null", () => {
|
||||||
|
expect(serializeMcpToolResult(null)).toBe("null");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("serializes void results as the string null so MCP content text is always a string", () => {
|
||||||
|
expect(serializeMcpToolResult(undefined)).toBe("null");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export function serializeMcpToolResult(result: unknown): string {
|
||||||
|
return JSON.stringify(result) ?? "null";
|
||||||
|
}
|
||||||
+2
-2
@@ -9,7 +9,7 @@ http {
|
|||||||
|
|
||||||
# Route websockets traffic to port 3001
|
# Route websockets traffic to port 3001
|
||||||
location /websockets {
|
location /websockets {
|
||||||
proxy_pass http://${HOSTNAME}:3001;
|
proxy_pass http://127.0.0.1:3001;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "Upgrade";
|
proxy_set_header Connection "Upgrade";
|
||||||
@@ -18,7 +18,7 @@ http {
|
|||||||
|
|
||||||
# Route all other traffic to port 3000
|
# Route all other traffic to port 3000
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://${HOSTNAME}:3000;
|
proxy_pass http://127.0.0.1:3000;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ async function importCookiesAsync() {
|
|||||||
|
|
||||||
function getBaseUrl() {
|
function getBaseUrl() {
|
||||||
if (typeof window !== "undefined") return window.location.origin;
|
if (typeof window !== "undefined") return window.location.origin;
|
||||||
return `http://${process.env.HOSTNAME ?? "localhost"}:3000`;
|
return "http://127.0.0.1:3000";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const trpcPath = "/api/trpc";
|
export const trpcPath = "/api/trpc";
|
||||||
|
|||||||
+6
-5
@@ -21,20 +21,18 @@ fi
|
|||||||
export AUTH_SECRET=$(openssl rand -base64 32)
|
export AUTH_SECRET=$(openssl rand -base64 32)
|
||||||
|
|
||||||
# Start nginx proxy
|
# Start nginx proxy
|
||||||
# 1. Replace the HOSTNAME in the nginx template file
|
# 1. Create the nginx configuration file from the template
|
||||||
# 2. Create the nginx configuration file from the template
|
# 2. Start the nginx server
|
||||||
# 3. Start the nginx server
|
|
||||||
# Only listen on IPv6 when the host actually has IPv6 configured (#4596).
|
# Only listen on IPv6 when the host actually has IPv6 configured (#4596).
|
||||||
# Otherwise nginx aborts with "socket() [::]:7575 failed (97: Address family
|
# Otherwise nginx aborts with "socket() [::]:7575 failed (97: Address family
|
||||||
# not supported by protocol)". Check HOMARR_DISABLE_IPV6 first so users can
|
# not supported by protocol)". Check HOMARR_DISABLE_IPV6 first so users can
|
||||||
# force IPv4-only even when the host supports IPv6, then probe for IPv6
|
# force IPv4-only even when the host supports IPv6, then probe for IPv6
|
||||||
# addresses via grep (not -s: proc files always report size 0).
|
# addresses via grep (not -s: proc files always report size 0).
|
||||||
export HOSTNAME
|
|
||||||
export NGINX_LISTEN_IPV6=''
|
export NGINX_LISTEN_IPV6=''
|
||||||
if [ "${HOMARR_DISABLE_IPV6:-false}" != "true" ] && grep -q . /proc/net/if_inet6 2>/dev/null; then
|
if [ "${HOMARR_DISABLE_IPV6:-false}" != "true" ] && grep -q . /proc/net/if_inet6 2>/dev/null; then
|
||||||
NGINX_LISTEN_IPV6='listen [::]:7575;'
|
NGINX_LISTEN_IPV6='listen [::]:7575;'
|
||||||
fi
|
fi
|
||||||
envsubst '${HOSTNAME} ${NGINX_LISTEN_IPV6}' < /etc/nginx/templates/nginx.conf > /etc/nginx/nginx.conf
|
envsubst '${NGINX_LISTEN_IPV6}' < /etc/nginx/templates/nginx.conf > /etc/nginx/nginx.conf
|
||||||
# Start services in the background and store their PIDs
|
# Start services in the background and store their PIDs
|
||||||
nginx -g 'daemon off;' &
|
nginx -g 'daemon off;' &
|
||||||
NGINX_PID=$!
|
NGINX_PID=$!
|
||||||
@@ -67,6 +65,9 @@ terminate() {
|
|||||||
|
|
||||||
trap terminate TERM INT
|
trap terminate TERM INT
|
||||||
|
|
||||||
|
# Next.js standalone uses HOSTNAME as its bind address. Docker's generated
|
||||||
|
# hostname can be unresolvable, so bind explicitly while nginx uses loopback.
|
||||||
|
export HOSTNAME=0.0.0.0
|
||||||
node apps/nextjs/server.js &
|
node apps/nextjs/server.js &
|
||||||
NEXTJS_PID=$!
|
NEXTJS_PID=$!
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user