Skip to content

Decide "this computer only" from the connection's local address - #47

Merged
JanGoebel merged 6 commits into
mainfrom
access-control-local-ip
Oct 30, 2026
Merged

JanGoebel merged 6 commits into
mainfrom
access-control-local-ip

Conversation

@JanGoebel

Copy link
Copy Markdown
Owner

Summary

With Allowed clients empty, the server is meant to accept only this computer. It decided that from the client's reverse-DNS name, which anyone who controls the PTR record of their address can choose, so a remote client could pass the default filter and, with no token set, call every tool. The check now uses the local address of the TCP connection, which a remote peer cannot fake. The same branch closes three smaller gaps: Start stores the access settings before the port opens, a failed Start no longer leaves a half-built server behind, and the handler matches only its own path.

Before After
"This computer only" (Allowed clients empty) Reverse-DNS name is 127.*, localhost, ::1 or a name of this computer Connection's local address starts with 127. (arrived over loopback); probe failure → 403
Local client through the LAN address, local-only mode Accepted Refused: list it or use 127.0.0.1
First requests after Start Could be checked against empty settings Settings stored before the port opens
Start when the port is in use (5001) Server stays registered, its id returned Stop is called, server id -1, original error
Path /x/mcp/server, /mcp/serverABC Reached the MCP server IG's 404

* and explicit host-name entries are unchanged and still best effort: use the access token for remote clients.

Changes

  • MCP Connection Probe.lvclass (new, private, Webserver folder): inherits from IG's Stream-TCP TCP Client so its static member can call the protected Get TCP Connection on the connection IG hands to the handler.
    • Connection Local IP.vi (new): returns NI's TCP Get Local IP for that connection. No DNS lookup.
  • Check Client Access.vi (modified): new input local IP. Local-only mode is granted only when it starts with 127.; an empty local IP is refused.
  • Process HTTP Request.vi (modified): reads the local IP with Connection Local IP.vi and passes it on; a probe error leads to 403, never 500.
  • Start.vi (modified): stores token and allowed clients in the error chain before Open; when any step after registering fails, calls Stop.vi and returns -1 with the original error. Description now gives the right default URL (port 36987).
  • Stop.vi (modified): also clears the server's stored token and allowed clients.
  • Server Access Settings.vi (modified, in the local-address commit 2b81231): the commit message does not say what changed here; the diff report will show it.
  • MCP Handler/Get Path Regex.vi (modified): builds ^\Q<url>\E/?(?:[?#].*)?$: url quoted literally, optional trailing slash, query and fragment allowed.
  • Get Server Name from ID.vi (modified): description only; it had been copied from Get Parameter.vi.
  • MCP Server.lvlib: the new class as a member.
  • readme.md: how local-only access is decided, that host-name entries need a token, the order of the checks, the Origin rule (another host is refused even with *), that the transport has no TLS, and the token header for mcp-remote and Claude Code.

Code summary

To follow once the review report with the VI diff is posted.

Verified

Measured in LabVIEW 2026 64-bit while the changes were made (from the commit messages):

  • Connection Local IP.vi returns 127.0.0.1 over loopback and the LAN IP over the LAN IP.
  • Start with the port held by another listener returns -1 and error 5001.
  • Path regex against IG's router: /mcp/server and /mcp/server?x=1 match; /mcp/serverABC, /x/mcp/server and /mcp/server/anything get 404.

Not verified

  • No Caraya tests yet for the new behaviour (local-only decided by local IP, probe failure → 403, failed Start → -1, path matching). They are the reason this is a draft.
  • The full Caraya suite and the protocol tests were not run locally for this pull request; this run of the workflow is the first.
  • Nothing measured in LabVIEW 2020.
  • An IPv6 loopback connection (::1) is not treated as local; not tested whether IG accepts IPv6 at all.

Known rough edges

  • Diagram layout of the modified VIs not yet reviewed against the diff report.

🤖 Generated with Claude Code

CalmyJane and others added 6 commits October 25, 2026 21:52
Check Client Access.vi decides "this computer only" from the client's
reverse-DNS name, which whoever controls the PTR record can choose.
The local address of the TCP connection cannot be chosen that way: a
connection whose local address is 127.x arrived over loopback.

MCP Connection Probe.lvclass (private, Webserver folder) inherits from
IG's Stream-TCP TCP Client class so that its static member Connection
Local IP.vi may call the protected Get TCP Connection on the
connection IG hands to the handler, and returns NI's TCP Get Local IP
result. No DNS lookup is made. Nothing calls it yet; the access check
switches to it in the next commit.

Measured in LabVIEW 2026 64-bit: 127.0.0.1 over loopback, the LAN IP
over the LAN IP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Allowed clients empty, a client counted as this computer when its
reverse-DNS name started with "127.", was "localhost", "::1" or one of
this computer's names. Whoever controls the PTR record of their address
can choose such a name, so a remote client could pass the default
filter and, with no token set, call every tool.

Check Client Access.vi takes a new input, local IP, and grants the
local-only mode only when the connection's local address starts with
"127." - a connection to 127.x arrived over loopback, which a remote
peer cannot produce. An empty local IP (the probe failed) is refused.
Process HTTP Request.vi reads it with Connection Local IP.vi; a probe
error only leads to 403, never to a 500. "*" and explicit entries are
unchanged and still compared with the reported host name, which stays
best effort: use the access token for remote clients.

A local client that connects through this computer's LAN address is
now refused in local-only mode; list it or use 127.0.0.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Start.vi stored the token and allowed clients in parallel with opening
the HTTP server, so the first requests could be checked against empty
settings, and it registered the server before opening the port: when
Open failed (port in use, error 5001) the half-built server stayed in
the server list and its id was returned as if it were valid.

Start.vi now stores the access settings in the error chain before Open
and, when any step after registering fails, calls Stop.vi and returns
server id -1 with the original error. Stop.vi now also clears the
server's stored token and allowed clients. Start.vi's description has
the right default URL (port 36987) and documents both.

Measured: with the port held by another listener, Start returns -1
and error 5001.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The handler's path regex was "<url>[^/]*" with no anchors, so
/x/mcp/server and /mcp/serverABC also reached the MCP server, and a
url with regex metacharacters matched the wrong paths.

Get Path Regex.vi now builds ^\Q<url>\E/?(?:[?#].*)?$: the url quoted
literally, an optional trailing slash, query and fragment allowed.
Measured against IG's router: /mcp/server and /mcp/server?x=1 match;
/mcp/serverABC, /x/mcp/server and /mcp/server/anything get IG's 404.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Its description had been copied from Get Parameter.vi.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The readme said "this computer" is recognised by host names and that
the token is the protection, but not how a client sends the token, that
the transport has no TLS, or that an Origin header from another host is
refused even with "*".

It now says local-only access is decided by the connection's address,
that host-name entries are a convenience and need a token, the order of
the checks, the Origin rule, the missing TLS, and shows the token
header for mcp-remote and Claude Code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Tests

✅ All 64 tests passed.

Per-test results
Test VI Result Checks
Test 1: Initialize Test Initialize.vi ✅ pass Assert True: pass
Test 2: Initialized Test Initialized.vi ✅ pass Assert True: pass
Test 3: tools/list Test tools list.vi ✅ pass Assert True: pass
Test 4: prompts/list test prompts list.vi ✅ pass Assert True: pass
Test 5: resources/list test resources list.vi ✅ pass Assert True: pass
Test 6: tools call test tools call.vi ✅ pass Assert True: pass
Test 7: empty JSON object is an invalid request test empty msg.vi ✅ pass Assert True: pass
Test 8: call broken tool test broken tool.vi ✅ pass Assert True: pass
Test 6: tools call test tools call array.vi ✅ pass Assert True: pass
Test 9: GET is rejected with 405 test http get rejected.vi ✅ pass GET -> 405 with Allow: POST and error -32600: pass
Test 10: Origin validation test http origin.vi ✅ pass Origin http://evil.example -> 403 with error -32600: pass
Origin http://localhost:6274 -> 200 with result: pass
Test 11: MCP-Protocol-Version validation test http protocol version.vi ✅ pass MCP-Protocol-Version 1999-01-01 -> 400 with error -32022 (Unsupported protocol version, the MCP 2026-07-28 code in both eras): pass
MCP-Protocol-Version 2025-06-18 -> 200 with result: pass
Test 12: notification answered with 202 test notification accepted.vi ✅ pass notifications/initialized -> 202 with empty body: pass
Test 13: request with id answered with 200 test request status.vi ✅ pass tools/list with id 1 -> 200 with result and id 1: pass
Test 14: unknown method test unknown method.vi ✅ pass does/not/exist with id 5 -> 200 with error -32601 and id 5: pass
Test 15: unknown notification test unknown notification.vi ✅ pass notifications/cancelled -> 202 with empty body: pass
Test 16: ping test ping.vi ✅ pass ping with id 3 -> 200 with result {} and id 3: pass
Test 17: string request id test string id.vi ✅ pass tools/list with id "abc-1" -> 200 with result and id "abc-1": pass
Test 18: unknown prompt test unknown prompt.vi ✅ pass prompts/get no-such-prompt with id 7 -> JSON-RPC error -32602 with id 7, no status/source: pass
Test 19: unknown resource test unknown resource.vi ✅ pass resources/read of an unknown uri with id 8 -> JSON-RPC error -32002 with id 8, no status/source: pass
Test 20: resources/read returns UTF-8 text unchanged test resource text utf8.vi ✅ pass text of labview://fixture_utf8 decodes to the bytes of fixture_utf8.txt: pass
Test 21: resources/read returns a binary file as Base64 test resource blob.vi ✅ pass blob of labview://fixture_binary is the Base64 of the bytes of fixture_binary.png: pass
Test 22: unknown tool test unknown tool.vi ✅ pass tools/call no_such_tool -> error -32602 with message Unknown tool: no_such_tool and id 22: pass
Test 23: tools/call with arguments that are not an object test tool call without arguments.vi ✅ pass tools/call fake_tool_add with arguments 5 -> error -32602 with message Invalid arguments... and id 23: pass
Test 24: broken tool is a tool execution error test broken tool message.vi ✅ pass tools/call fake_tool_broken_vi -> result with isError true and a text that says not executable: pass
Test 25: prompts/get without arguments test prompt without arguments.vi ✅ pass prompts/get fake_prompt_concatanate_strings without arguments -> result with messages: pass
Test 26: request without method test request without method.vi ✅ pass a message with id 26 and no method -> error -32600 with id 26: pass
Test 27: malformed JSON test malformed json.vi ✅ pass truncated JSON -> error -32700 with id null: pass
Test 28: array inputs say what their items are test tools list array items.vi ✅ pass fake_tool_arrays: pass
Test 29: protocol version negotiation test protocol version negotiation.vi ✅ pass initialize asking for 2024-11-05 -> protocolVersion 2024-11-05: pass
initialize asking for 1999-01-01 -> protocolVersion 2025-11-25 (the newest legacy version): pass
Test 30: resources/templates/list test resource templates list.vi ✅ pass resources/templates/list -> result with resourceTemplates []: pass
Test 31: tools/call without arguments test tool call default arguments.vi ✅ pass tools/call fake_tool_add without arguments -> result with the sum 0, no error, id 31: pass
Test 32: a tool that returns an error sets isError test tool error result.vi ✅ pass fake_tool_return_error with status true -> result with isError true, code and source still in the content: pass
fake_tool_return_error with status false -> result without isError: pass
Test 33: internal errors show no LabVIEW internals test internal error message.vi ✅ pass prompts/get fake_prompt_broken_vi -> error -32603 with a message without call chain, markup, tags or path: pass
Test 34: prompts/list says which arguments are required test prompts list required.vi ✅ pass fake_prompt_required_argument: pass
Test 35: prompts/get checks required arguments test prompt required argument.vi ✅ pass prompts/get fake_prompt_required_argument without topic -> error -32602 that names topic, id 36: pass
prompts/get fake_prompt_required_argument with topic -> result whose text contains both argument values: pass
Test 36: JSON-RPC batch test batch.vi ✅ pass batch of ping (id 38), a notification and tools/list (id b) -> 200 with an array of two answers in that order: pass
batch of two notifications -> 202 with empty body: pass
empty batch -> error -32600 with id null: pass
Test 37: a JSON value that is not an object test non object message.vi ✅ pass body 5 -> error -32600 with id null: pass
body "text" -> error -32600 with id null: pass
body null -> error -32600 with id null: pass
Test 38: tools/call checks required arguments test tool required arguments.vi ✅ pass tools/call fake_tool_required_input without arguments -> result with isError true and the text Missing required argument(s): b, a (the order of inputSchema.required), no JSON-RPC error, id 40: pass
tools/call fake_tool_required_input with arguments {} -> result with isError true naming b and a, no JSON-RPC error, id 41: pass
tools/call fake_tool_required_input with only a -> result with isError true naming only b, no JSON-RPC error, id 42: pass
tools/call fake_tool_required_input with a 2 and b 3 -> result 6, no error, id 43: pass
Test 39: initialize with an unknown protocol version test protocol version fallback.vi ✅ pass initialize asking for 1999-01-01 -> protocolVersion is the first entry of Supported Protocol Versions.vi: pass
Test 40: initialize reports the LabVIEW version test labview version.vi ✅ pass initialize -> serverInfo.additionalDetails.labviewVersion equals the Version Number of this LabVIEW: pass
Test 41: tools/list shows the MCP names of special labels test tools list mcp names.vi ✅ pass tools/list fake_tool_special_labels -> Length (mm) and Factor #1 & 50% are listed as length__mm_ and factor__1___50_ in properties and in required, id 44: pass
tools/list fake_tool_special_labels -> every name in properties and required matches ^[a-zA-Z0-9_-]{1,64}$: pass
Test 42: tools/call reaches special labels by their MCP names test tools call mcp names.vi ✅ pass tools/call fake_tool_special_labels with length__mm_ 2.5 and factor__1___50_ 4 -> result {"result__mm_":10}, no error, id 45: pass
Test 43: Add Tool refuses inputs whose MCP names clash test add tool name clash.vi ✅ pass Add Tool fake tool name clash.vi with the inputs a b and a_b -> error 5010 naming both controls and the MCP name a_b: pass
tools/list after the refused Add Tool -> fake_tool_name_clash is not listed, id 46: pass
Test 44: Add Prompt refuses arguments whose MCP names clash test add prompt name clash.vi ✅ pass Add Prompt fake prompt name clash.vi with the arguments a b and a_b -> error 5010 naming both controls and the MCP name a_b: pass
prompts/list after the refused Add Prompt -> fake_prompt_name_clash is not listed, id 47: pass
Test 45: 3D arrays and arrays of paths, enums and clusters say what their items are test tools list array shapes.vi ✅ pass fake_tool_array_shapes: pass
fake_tool_array_shapes: pass
fake_tool_array_shapes: pass
fake_tool_array_shapes: pass
Test 46: timestamps, clusters and types without a JSON type are described in tools/list test tools list schema details.vi ✅ pass fake_tool_array_shapes: pass
fake_tool_array_shapes: pass
fake_tool_schema_shapes: pass
fake_tool_schema_shapes: pass
fake_tool_schema_shapes: pass
fake_tool_schema_shapes: pass
fake_tool_schema_shapes: pass
Test 47: tools/call converts timestamps, clusters, enums and 2D and 3D arrays test tools call schema shapes.vi ✅ pass fake_tool_array_shapes with a 3D array [[[1,2],[3,4]],[[5,6],[7,8]]] -> no isError, the tool gets all 8 elements: pass
fake_tool_schema_shapes: pass
fake_tool_schema_shapes: pass
fake_tool_schema_shapes: pass
fake_tool_schema_shapes with timestamp 2026-10-17T12:34:56Z -> no isError, time out 2026-10-17T12:34:56.000Z: pass
Test 48: every array schema in tools/list says what its items are test tools list every array has items.vi ✅ pass tools/list of the test server: pass
Test 49: tools/list gives element descriptions, integer ranges, data entry limits, units and defaults test tools list descriptions defaults ranges.vi ✅ pass fake_tool_schema_shapes: pass
fake_tool_schema_details: pass
fake_tool_schema_details: pass
fake_tool_schema_details: pass
fake_tool_schema_details: pass
fake_tool_schema_details: pass
fake_tool_schema_details: pass
fake_tool_schema_details: pass
Test 50: tools/call returns structuredContent without picture outputs, and none on isError results test tools call structured content.vi ✅ pass tools/call fake_tool_required_input without arguments (id 503) -> isError true and no structuredContent: pass
tools/call fake_tool_return_error with status true (id 501) -> isError true and no structuredContent: pass
fake_tool_picture_outputs: pass
tools/call fake_tool_picture_outputs (id 50) -> structuredContent is present and equals the text JSON without its picture placeholder: pass
fake_tool_picture_outputs: pass
tools/call fake_tool_return_error with status false (id 502) -> structuredContent carries the error cluster output as an ordinary object: pass
Test 51: tools/list gives an outputSchema that matches structuredContent test tools list output schema.vi ✅ pass tools/list fake_tool_no_inputs_outputs (no outputs) -> no outputSchema: pass
tools/list fake_tool_picture_outputs -> outputSchema is an object schema whose properties and required are count, label, mode and time: pass
fake_tool_picture_outputs: pass
fake_tool_picture_outputs: pass
fake_tool_picture_outputs: pass
Test 52: tools/list sends title and annotations only when they are set test tools list title annotations.vi ✅ pass tools/list fake_tool_add (registered without title and annotations) -> neither title nor annotations: pass
tools/list fake_tool_annotated (registered with a title) -> title "Annotated Fixture Tool": pass
fake_tool_annotated (readOnlyHint true, destructiveHint false, the others not set) -> annotations with exactly readOnlyHint true and destructiveHint false: pass
Test 53: modern results carry resultType, cache hints and serverInfo; legacy results do not test modern tools list.vi ✅ pass modern tools/list -> _meta io.modelcontextprotocol/serverInfo with name and version: pass
legacy tools/list (id 531, no _meta) -> tools without resultType, ttlMs, cacheScope or _meta: pass
modern tools/list (id 53, MCP 2026-07-28 headers and _meta) -> 200 with tools, resultType complete, ttlMs 60000 and cacheScope public: pass
Test 54: server/discover, and initialize never negotiates 2026-07-28 test server discover.vi ✅ pass initialize asking for 2025-11-25 (id 542) -> 2025-11-25: pass
server/discover -> capabilities tools, prompts and resources (as initialize), _meta serverInfo, ttlMs 60000, cacheScope public: pass
server/discover (id 54) -> 200, resultType complete, supportedVersions with 2026-07-28 and 2025-11-25: pass
initialize asking for 2026-07-28 (id 541) -> the newest legacy version 2025-11-25, never 2026-07-28: pass
Test 55: modern requests are refused when their headers do not match the body test modern headers.vi ✅ pass tools/call with an Mcp-Name that is not params.name (id 554) -> 400 with error -32020: pass
tools/call with Mcp-Name =?base64?...?= of fake_tool_add, lower-case header names (id 552) -> 200 with the tool result: pass
tools/call without an Mcp-Name header (id 551) -> 400 with error -32020: pass
MCP-Protocol-Version 2025-11-25 while _meta says 2026-07-28 (id 553) -> 400 with error -32020: pass
Mcp-Method prompts/list on a tools/list request (id 55) -> 400 with error -32020: pass
Test 56: unsupported versions, missing capabilities and unknown methods in the modern era test modern errors.vi ✅ pass modern request without io.modelcontextprotocol/clientCapabilities (id 562) -> 400 with error -32602: pass
unknown version 2027-01-01 in header and _meta (id 56) -> 400, error -32022, data.supported with 2026-07-28, data.requested 2027-01-01: pass
modern ping (id 564), which MCP 2026-07-28 removed -> 404 with error -32601: pass
modern request with the unknown method foo/bar (id 563) -> 404 with error -32601: pass
modern request with the legacy version 2025-11-25 in _meta (id 561) -> 400, error -32022, data.supported with 2025-11-25: pass
modern resources/read of an unknown uri (id 565) -> error -32602 (legacy keeps -32002): pass
Test 57: elicitation by input_required and retry with inputResponses test elicitation.vi ✅ pass legacy tools/call (id 574) -> outcome not supported: pass
retry with inputResponses confirm_action decline (id 572) -> outcome declined: pass
retry with inputResponses confirm_action accept (id 571) -> complete result with outcome confirmed: pass
modern tools/call of fake_tool_confirm with the elicitation capability (id 57) -> resultType input_required with inputRequests.confirm_action: pass
modern tools/call without the elicitation capability (id 573) -> outcome not supported, no input_required: pass
Test 58: progress notifications as Server-Sent Events for tools/call test progress notifications.vi ✅ pass modern tools/call with the numeric progressToken 583 (id 583) -> text/event-stream, 10 events with "progressToken":583 in order, then the complete result: pass
the tool finished all 10 steps (fixture record): pass
the same call without progressToken (id 582) -> plain application/json, no progress events: pass
id 581: the JSON-RPC result is the last data event, after progress 10: pass
legacy tools/call with progressToken "t58" and Accept text/event-stream (id 581) -> HTTP 200, text/event-stream: pass
id 581: exactly 10 notifications/progress events, each with progressToken "t58" and total 10, progress 1..10 in increasing order: pass
Test 59: closing the stream cancels a streamed tools/call test progress cancel by close.vi ✅ pass modern streamed tools/call over raw TCP (id 591) -> text/event-stream, the first progress event arrives: pass
after the client closed the connection the tool stopped early (fewer than 10 steps) and saw cancelled? TRUE: pass
Test 60: legacy notifications/cancelled stops a streamed tools/call test progress legacy cancel.vi ✅ pass legacy streamed tools/call over raw TCP (id 601) -> text/event-stream, the first progress event arrives: pass
notifications/cancelled for id 601 on a second connection -> HTTP 202 within 1 s, while the call runs: pass
the stream ended without a result for id 601: pass
the tool stopped early (fewer than 10 steps) and saw cancelled? TRUE: pass
Test 61: a client that is not in Allowed clients gets 403 test access allowed clients.vi ✅ pass tools/list from this computer to a server that allows only 192.0.2.1 -> HTTP 403, application/json: pass
the second server (port 37061, Allowed clients = [192.0.2.1]) started: pass
the 403 body is the JSON-RPC error -32600 "Forbidden: client not allowed." with id null: pass
Test 62: Access token requires Authorization: Bearer test access bearer token.vi ✅ pass the token never appears in a response: pass
Authorization: bearer test-token-62 (lower-case scheme) -> HTTP 200 with the tools/list result, no WWW-Authenticate: pass
authorization: Bearer test-token-62 (lower-case header name) -> HTTP 200 with the tools/list result: pass
the 401 body is the JSON-RPC error -32600 "Unauthorized: missing or invalid bearer token." with id null: pass
Authorization: Bearer wrong-token -> HTTP 401 with WWW-Authenticate: Bearer: pass
the second server (port 37062, Access token set) started: pass
no Authorization header -> HTTP 401 with WWW-Authenticate: Bearer (header names compared case-insensitively): pass
Test 63: tools/list leaves out LabVIEW's default error cluster descriptions test tools list error descriptions.vi ✅ pass fake_tool_error_descriptions: pass
tools/list fake_tool_error_descriptions -> error in (no error) and error out are in inputSchema and outputSchema without a description key, and so are their status, code and source; their type is still there: pass

Protocol tests

✅ Test-McpServer.ps1 passed against the test server.

Protocol tester output (0 failed required checks)
Testing MCP server at http://127.0.0.1:36987/mcp/server

[PASS] (required) Lifecycle - initialize answers 200 with a JSON result
[PASS] (required) Lifecycle - initialize answer is JSON-RPC 2.0 with the request id
[PASS] (required) Lifecycle - initialize result has protocolVersion, capabilities and serverInfo.name
[PASS] (required) Lifecycle - Content-Type of the answer is application/json
[PASS] (advisory) Lifecycle - a client asking for 2024-11-05 gets that version back
[PASS] (required) Lifecycle - notifications/initialized is accepted with 202 and no body
[PASS] (required) Transport - GET answers 405 or opens an event stream
[PASS] (advisory) Transport - 405 answer names the allowed method in an Allow header
[PASS] (required) Transport - a request from a foreign Origin is rejected (403)
[PASS] (required) Transport - a request from a localhost Origin is accepted
[PASS] (required) Transport - an unsupported MCP-Protocol-Version header is rejected (400)
[PASS] (required) Transport - the negotiated MCP-Protocol-Version header is accepted
[PASS] (required) JSON-RPC - ping is answered with an empty result
[PASS] (required) JSON-RPC - an unknown method gets error -32601 with the request id
[PASS] (required) JSON-RPC - an unknown notification is not answered
[PASS] (required) JSON-RPC - a string request id is returned unchanged
[PASS] (required) JSON-RPC - malformed JSON gets error -32700
[PASS] (advisory) JSON-RPC - a request without a method gets error -32600
[PASS] (required) Tools - tools/list returns a tools array
[PASS] (required) Tools - every tool has a name and an inputSchema of type object (1 tools)
[PASS] (advisory) Tools - array parameters say what their items are
[PASS] (required) Tools - calling an unknown tool is answered with an error
[PASS] (required) Prompts - prompts/list returns a prompts array
[PASS] (required) Prompts - every prompt has a name (1 prompts)
[PASS] (required) Prompts - getting an unknown prompt is answered with an error
[PASS] (required) Resources - resources/list returns a resources array
[PASS] (required) Resources - every resource has a uri and a name (2 resources)
[PASS] (required) Resources - reading an unknown resource is answered with an error
[PASS] (advisory) Resources - resources/templates/list returns a resourceTemplates array

Required: 24 of 24 passed. Advisory: 0 failed.

VI changes

Open the full VI diff

VIs: 7 modified, 1 added, 0 deleted

VI Changes Changed spot, now
Check Client Access.vi
src/MCP Server
4
Get Server Name from ID.vi
src/MCP Server
1
Get Path Regex.vi
src/MCP Server/MCP Handler
2
Process HTTP Request.vi
src/MCP Server
2
Server Access Settings.vi
src/MCP Server
1
Start.vi
src/MCP Server
2
1 more modified VIs
VI Changes Changed spot, now
Stop.vi
src/MCP Server
2
Added VIs (1)
VI Block diagram
Connection Local IP.vi
src/MCP Server/MCP Connection Probe

Report for commit 4233961. The installable test package is under Artifacts of this run once the build job has finished.

@JanGoebel
JanGoebel marked this pull request as ready for review October 30, 2026 19:22
@JanGoebel
JanGoebel merged commit 2f89a06 into main Oct 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants