nsmcp::HttpTransport method request (public)

 <instance of nsmcp::HttpTransport[i]> request method headers body \
    server

Defined in /usr/local/ns/tcl/nsmcp/transport.tcl

Header dictionary uses lower-case keys; created by Server.http.

Parameters:
method (required)
headers (required)
body (required)
server (required)

Testcases:
No testcase defined.
Source code:
try {
    if {[dict exists $headers origin] &&
        [dict get $headers origin] ni ${:allowedOrigins}} {
        return [:response 403 "Origin not permitted"]
    }
    set authorization {}
    if {[dict exists $headers authorization]} {set authorization [dict get $headers authorization]}
    if {[catch {${:authenticator} authenticate $authorization $server} context options]} {
        set ec [dict get $options -errorcode]
        if {[lrange $ec 0 1] eq {NSMCP HTTP}} {
            return [:response [lindex $ec 2] "Authentication required"  [dict create WWW-Authenticate {Bearer realm="nsmcp"}]]
        }
        ns_log error "nsmcp: authentication adapter failed"
        return [:response 500 "Internal error"]
    }
    if {$server ni [$context targets]} {return [:response 403 "Target not permitted"]}
    if {$method ne "POST"} {return [:response 405 "Method not allowed" [dict create Allow POST]]}
    if {[dict exists $headers mcp-protocol-version] &&
        ![${:protocol} supports [dict get $headers mcp-protocol-version]]} {
        return [:response 400 "Unsupported protocol version"]
    }
    if {![dict exists $headers content-type] ||
        [:mediaTypes [dict get $headers content-type]] ne {application/json}} {
        return [:response 415 "Expected application/json"]
    }
    if {![dict exists $headers accept]} {return [:response 406 "Missing Accept header"]}
    set accepted [:mediaTypes [dict get $headers accept]]
    if {"application/json" ni $accepted || "text/event-stream" ni $accepted} {
        return [:response 406 "Accept must include application/json and text/event-stream"]
    }
    if {[string length [encoding convertto utf-8 $body]] > ${:maxBodyBytes}} {
        return [:response 413 "Request body too large"]
    }
    if {[dict exists $headers x-nsmcp-question]} {
        set key [dict get $headers x-nsmcp-question]
        if {[catch {:questionPolicy $context $key} observer]} {return [:response 403 "Question policy expired, unavailable or credential scope not permitted"]}
        if {[catch {ns_json parse -top container -- $body} request]} {return [:response 400 "Invalid question request"]}
        if {[dict exists $request method] && [dict get $request method] eq "tools/call"} {
            set limit [ns_config -int ns/server/$server/module/nsmcp questionMaxToolCalls 32]
            if {$limit<1 || [nsv_incr nsmcp:question-call-count $key]>$limit} {return [:response 403 "Question tool-call budget exceeded"]}
        }
    }
    set response [${:protocol} handle $context $body]
    if {[dict exists $headers x-nsmcp-question] && [nsf::object::exists ::nsmcp::QuestionJobPoller]} {
        set key [dict get $headers x-nsmcp-question]
        if {[regexp {^[0-9a-f]{64}$} $key] && [nsv_exists nsmcp:question-observers $key] && [nsv_get nsmcp:question-observers $key observer]
            && [dict get $observer principal] eq [$context principal]
            && [dict get $observer server] eq $server && [dict get $observer deadline]>[clock milliseconds]} {
            set request [ns_json parse $body]
            if {[dict exists $request method] && [dict get $request method] eq "tools/call"
                && [dict get $response status]==200 && [dict get $response body] ne ""} {
                set root [ns_json parse -output triples -- [dict get $response body]]
                if {![catch {ns_json triples getvalue -output triples -path result -- $root} result]} {
                    set json [::nsmcp::QuestionJobPoller wait [dict get $request params name]  [ns_json value -- [list {} object $result]] [dict get $observer deadline]  [dict get $observer emit] [list [self] questionPoll $authorization $server $key]]
                    set fields {}
                    foreach {k t v} [lindex $root 2] {
                        if {$k eq "result"} {set v [lindex [ns_json parse -output triples -- $json] 2]}
                        lappend fields $k $t $v
                    }
                    dict set response body [ns_json value -- [list {} object $fields]]
                }
            }
        }
    }
    dict set response headers [dict create Content-Type {application/json; charset=utf-8}]
    ns_log debug "nsmcp: principal=[ns_json value -type string -- [$context principal]] target=[ns_json value -type string -- $server] status=[dict get $response status]"
    return $response
} finally {
    # Immediate cleanup plus the deallocate hook as a fallback for aborts.
    ::nsmcp::cleanup
}
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: