[{"data":1,"prerenderedAt":1719},["ShallowReactive",2],{"route-doc-meta:\u002Futcp":3,"page-dates:\u002Futcp":3,"utcp-content":4},null,{"id":5,"title":6,"body":7,"description":1714,"extension":1715,"meta":1716,"navigation":715,"path":28,"seo":1717,"stem":13,"__hash__":1718},"content\u002Futcp.md","UTCP",{"type":8,"value":9,"toc":1699},"minimark",[10,14,36,51,56,63,78,162,181,185,188,360,369,373,417,420,423,474,487,494,499,529,533,536,642,655,658,686,1087,1093,1097,1115,1446,1449,1460,1545,1549,1553,1556,1564,1610,1614,1627,1692,1695],[11,12,6],"h1",{"id":13},"utcp",[15,16,17,18,24,25,29,30,35],"p",{},"Unified.to publishes its tools as a ",[19,20,6],"a",{"href":21,"rel":22},"https:\u002F\u002Fwww.utcp.io",[23],"nofollow"," (Universal Tool Calling Protocol) manual at ",[26,27,28],"code",{},"\u002Futcp",". A UTCP client reads the manual and then calls the Unified API directly over HTTP. The tools, permissions and billing are the same as on the ",[19,31,34],{"href":32,"rel":33},"https:\u002F\u002Fdocs.unified.to\u002Fmcp\u002Foverview",[23],"MCP server",", but UTCP is a separate protocol: there is no MCP connection involved.",[37,38,39],"blockquote",{},[15,40,41,45,46,50],{},[42,43,44],"strong",{},"For agents:"," this page is also available as Markdown at ",[19,47,48],{"href":48,"rel":49},"https:\u002F\u002Fdocs.unified.to\u002Futcp.md",[23],".",[52,53,55],"h2",{"id":54},"what-is-utcp","What is UTCP",[15,57,58,59,62],{},"The ",[42,60,61],{},"Universal Tool Calling Protocol"," (UTCP) is an open standard for describing tools so that an agent can call them over their own protocol: HTTP, a CLI, WebSocket and others. There is no protocol server in between.",[15,64,65,66,69,70,73,74,77],{},"A UTCP server publishes a ",[42,67,68],{},"manual",": a JSON document that lists each tool's name, description, input and output JSON schemas, and a ",[42,71,72],{},"call template",". The call template says how to make the call, for example \"POST to this URL, send this argument as the JSON body, put the API key in the ",[26,75,76],{},"Authorization"," header\". The client fetches the manual once, then calls each tool itself.",[79,80,81,95],"table",{},[82,83,84],"thead",{},[85,86,87,90,93],"tr",{},[88,89],"th",{},[88,91,92],{},"MCP",[88,94,6],{},[96,97,98,114,132,151],"tbody",{},[85,99,100,104,111],{},[101,102,103],"td",{},"How a tool is called",[101,105,106,107,110],{},"JSON-RPC ",[26,108,109],{},"tools\u002Fcall"," to an MCP server",[101,112,113],{},"A plain HTTP request built from the tool's call template",[85,115,116,119,125],{},[101,117,118],{},"Discovery",[101,120,121,124],{},[26,122,123],{},"tools\u002Flist"," on a live connection",[101,126,127,128,131],{},"One ",[26,129,130],{},"GET"," of the manual",[85,133,134,137,148],{},[101,135,136],{},"Sessions",[101,138,139,140,143,144,147],{},"Stateful (up to ",[26,141,142],{},"2025-11-25",") or stateless (",[26,145,146],{},"2026-07-28",")",[101,149,150],{},"None",[85,152,153,156,159],{},[101,154,155],{},"Extras",[101,157,158],{},"Events, Agent Skills, OAuth discovery",[101,160,161],{},"None of these: tools only",[15,163,164,165,169,170,175,176,50],{},"Use UTCP when your agent framework already speaks UTCP, or when you want tool definitions that a client calls with ordinary HTTP. Use the ",[19,166,34],{"href":167,"rel":168},"https:\u002F\u002Fdocs.unified.to\u002Fmcp\u002Finstallation",[23]," for MCP clients (Claude, ChatGPT, Cursor, VS Code, …) and when you need ",[19,171,174],{"href":172,"rel":173},"https:\u002F\u002Fdocs.unified.to\u002Fmcp\u002Foverview#events-webhooks-for-agents",[23],"MCP Events"," or ",[19,177,180],{"href":178,"rel":179},"https:\u002F\u002Fdocs.unified.to\u002Fmcp\u002Fcore#agent-skills",[23],"Agent Skills",[52,182,184],{"id":183},"who-supports-utcp","Who supports UTCP",[15,186,187],{},"UTCP is younger than MCP and none of the major LLM providers support it natively yet. You use it through a client library or an adapter. As of November 2026:",[79,189,190,200],{},[82,191,192],{},[85,193,194,197],{},[88,195,196],{},"Kind",[88,198,199],{},"Project",[96,201,202,229,257,269,284,300,316,331,345],{},[85,203,204,207],{},[101,205,206],{},"Python",[101,208,209,215,216,223,224,147],{},[19,210,213],{"href":211,"rel":212},"https:\u002F\u002Fpypi.org\u002Fproject\u002Futcp\u002F",[23],[26,214,13],{}," with the ",[19,217,220],{"href":218,"rel":219},"https:\u002F\u002Fpypi.org\u002Fproject\u002Futcp-http\u002F",[23],[26,221,222],{},"utcp-http"," plugin (",[19,225,228],{"href":226,"rel":227},"https:\u002F\u002Fgithub.com\u002Funiversal-tool-calling-protocol\u002Fpython-utcp",[23],"python-utcp",[85,230,231,234],{},[101,232,233],{},"TypeScript \u002F Node.js",[101,235,236,243,244,251,252,147],{},[19,237,240],{"href":238,"rel":239},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@utcp\u002Fsdk",[23],[26,241,242],{},"@utcp\u002Fsdk"," with ",[19,245,248],{"href":246,"rel":247},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@utcp\u002Fhttp",[23],[26,249,250],{},"@utcp\u002Fhttp"," (",[19,253,256],{"href":254,"rel":255},"https:\u002F\u002Fgithub.com\u002Funiversal-tool-calling-protocol\u002Ftypescript-utcp",[23],"typescript-utcp",[85,258,259,262],{},[101,260,261],{},"Go",[101,263,264],{},[19,265,268],{"href":266,"rel":267},"https:\u002F\u002Fgithub.com\u002Funiversal-tool-calling-protocol\u002Fgo-utcp",[23],"go-utcp",[85,270,271,274],{},[101,272,273],{},"Rust",[101,275,276,283],{},[19,277,280],{"href":278,"rel":279},"https:\u002F\u002Fcrates.io\u002Fcrates\u002Frs-utcp",[23],[26,281,282],{},"rs-utcp"," (pre-1.0)",[85,285,286,289],{},[101,287,288],{},"MCP clients",[101,290,291,251,296,299],{},[19,292,295],{"href":293,"rel":294},"https:\u002F\u002Fgithub.com\u002Funiversal-tool-calling-protocol\u002Futcp-mcp",[23],"UTCP-MCP bridge",[26,297,298],{},"@utcp\u002Fmcp-bridge","): exposes UTCP manuals to any MCP client, eg. Claude Desktop or Claude Code",[85,301,302,305],{},[101,303,304],{},"Code execution",[101,306,307,251,312,315],{},[19,308,311],{"href":309,"rel":310},"https:\u002F\u002Fgithub.com\u002Funiversal-tool-calling-protocol\u002Fcode-mode",[23],"Code Mode",[26,313,314],{},"@utcp\u002Fcode-mode","): the agent writes code that calls UTCP and MCP tools",[85,317,318,321],{},[101,319,320],{},"LangChain \u002F LangGraph",[101,322,323,330],{},[19,324,327],{"href":325,"rel":326},"https:\u002F\u002Fpypi.org\u002Fproject\u002Flangchain-utcp-adapters\u002F",[23],[26,328,329],{},"langchain-utcp-adapters"," (early release)",[85,332,333,336],{},[101,334,335],{},"Pydantic AI",[101,337,338,330],{},[19,339,342],{"href":340,"rel":341},"https:\u002F\u002Fgithub.com\u002Funiversal-tool-calling-protocol\u002Fpydantic-ai-utcp",[23],[26,343,344],{},"pydantic-ai-utcp",[85,346,347,350],{},[101,348,349],{},"Strands Agents",[101,351,352,359],{},[19,353,356],{"href":354,"rel":355},"https:\u002F\u002Fstrandsagents.com\u002Fdocs\u002Fcommunity\u002Ftools\u002Futcp\u002F",[23],[26,357,358],{},"strands-utcp"," (community contribution)",[15,361,362,363,368],{},"There are also community libraries for Ruby, Elixir and Lua. See the ",[19,364,367],{"href":365,"rel":366},"https:\u002F\u002Fgithub.com\u002Funiversal-tool-calling-protocol",[23],"UTCP GitHub organization"," for the current list.",[52,370,372],{"id":371},"manual-urls","Manual URLs",[79,374,375,385],{},[82,376,377],{},[85,378,379,382],{},[88,380,381],{},"Region",[88,383,384],{},"Manual URL",[96,386,387,397,407],{},[85,388,389,392],{},[101,390,391],{},"US",[101,393,394],{},[26,395,396],{},"https:\u002F\u002Fapi.unified.to\u002Futcp",[85,398,399,402],{},[101,400,401],{},"EU",[101,403,404],{},[26,405,406],{},"https:\u002F\u002Fapi-eu.unified.to\u002Futcp",[85,408,409,412],{},[101,410,411],{},"AU",[101,413,414],{},[26,415,416],{},"https:\u002F\u002Fapi-au.unified.to\u002Futcp",[15,418,419],{},"Use the host for the region your workspace lives in: a credential only works on its own region's host, and every call URL in the manual points back to the host you fetched it from.",[15,421,422],{},"What the manual lists depends on the credential:",[79,424,425,435],{},[82,426,427],{},[85,428,429,432],{},[88,430,431],{},"Credential",[88,433,434],{},"Tools in the manual",[96,436,437,448,463],{},[85,438,439,445],{},[101,440,441,442],{},"A connection-scoped token, or a workspace API key with ",[26,443,444],{},"connection",[101,446,447],{},"That connection's integration tools",[85,449,450,455],{},[101,451,452,453],{},"A workspace API key without ",[26,454,444],{},[101,456,58,457,462],{},[19,458,461],{"href":459,"rel":460},"https:\u002F\u002Fdocs.unified.to\u002Fmcp\u002Fcore",[23],"Core Unified API"," tools: connections, integrations, webhooks, docs search, …",[85,464,465,467],{},[101,466,150],{},[101,468,469,470,473],{},"A preview of the Core tools, or with ",[26,471,472],{},"?integration_type=\u003Ctype>"," that integration's tools. Calls still need a credential",[15,475,476,477,480,481,486],{},"Authenticate with a workspace API key or a connection-scoped token, usually as ",[26,478,479],{},"Authorization: Bearer \u003Ckey>",". These are the same credentials the MCP server accepts; see ",[19,482,485],{"href":483,"rel":484},"https:\u002F\u002Fdocs.unified.to\u002Fmcp\u002Fauthentication",[23],"Authentication"," for how to create a connection-scoped token.",[15,488,489,490,493],{},"The manual never contains your credential. Every tool's call template uses ",[26,491,492],{},"Authorization: Bearer ${UNIFIED_API_KEY}",", and your UTCP client fills in the variable when it calls the tool.",[495,496,498],"h3",{"id":497},"variable-names","Variable names",[15,500,501,502,505,506,509,510,513,514,509,517,520,521,524,525,528],{},"UTCP clients add the manual's name as a prefix to each variable: underscores in the name are doubled, then ",[26,503,504],{},"_"," is added. If you register the manual as ",[26,507,508],{},"unified",", the client looks up ",[26,511,512],{},"unified_UNIFIED_API_KEY",". If you name it ",[26,515,516],{},"unified_crm",[26,518,519],{},"unified__crm_UNIFIED_API_KEY",". Clients take the value from their config's ",[26,522,523],{},"variables"," first, then from configured loaders such as a ",[26,526,527],{},".env"," file, then from the environment.",[495,530,532],{"id":531},"url-parameters","URL parameters",[15,534,535],{},"Add these to the manual URL. They narrow the tool list, and are copied into every call URL so the calls run against the same tools.",[79,537,538,546],{},[82,539,540],{},[85,541,542,544],{},[88,543],{},[88,545],{},[96,547,548,557,572,593,603,613,626,636],{},[85,549,550,554],{},[101,551,552],{},[26,553,444],{},[101,555,556],{},"The connection ID, when you authenticate with a workspace API key",[85,558,559,564],{},[101,560,561],{},[26,562,563],{},"permissions",[101,565,566,567],{},"A comma-delimited list of permissions from ",[19,568,571],{"href":569,"rel":570},"https:\u002F\u002Fdocs.unified.to\u002Fguides\u002Fhow_to_configure_webhooks_in_hubspot#select-permission-scopes-on-unifiedto",[23],"Unified.to",[85,573,574,579],{},[101,575,576],{},[26,577,578],{},"tools",[101,580,581,582,585,586,589,590],{},"A comma-delimited list of tool IDs. Supports the wildcards ",[26,583,584],{},"*"," and ",[26,587,588],{},"?",", eg. ",[26,591,592],{},"list_*,*invoice*",[85,594,595,600],{},[101,596,597],{},[26,598,599],{},"include_external_tools",[101,601,602],{},"Include an integration's tools from all of its API and not just the default supported unified API",[85,604,605,610],{},[101,606,607],{},[26,608,609],{},"hide_sensitive",[101,611,612],{},"Hides sensitive (ie. PII) data from results",[85,614,615,620],{},[101,616,617],{},[26,618,619],{},"aliases",[101,621,622,623],{},"Additional words for tool descriptions, in the format ",[26,624,625],{},"word1:alias1,alias2;word2:alias1,alias2",[85,627,628,633],{},[101,629,630],{},[26,631,632],{},"integration_type",[101,634,635],{},"Without a credential, preview that integration's tools",[85,637,638,640],{},[101,639],{},[101,641],{},[15,643,644,645,650,651,175,653,50],{},"These are the same options the MCP server takes; ",[19,646,649],{"href":647,"rel":648},"https:\u002F\u002Fdocs.unified.to\u002Fmcp\u002Fserver-options",[23],"Server Options"," describes each one in more detail. Most LLMs handle a few dozen tools at most, so limit the list with ",[26,652,563],{},[26,654,578],{},[52,656,206],{"id":657},"python",[659,660,665],"pre",{"className":661,"code":662,"language":663,"meta":664,"style":664},"language-bash shiki shiki-themes github-dark github-dark github-light","pip install utcp utcp-http\n","bash","",[26,666,667],{"__ignoreMap":664},[668,669,672,676,680,683],"span",{"class":670,"line":671},"line",1,[668,673,675],{"class":674},"s5n6i","pip",[668,677,679],{"class":678},"s4Y1p"," install",[668,681,682],{"class":678}," utcp",[668,684,685],{"class":678}," utcp-http\n",[659,687,690],{"className":688,"code":689,"language":657,"meta":664,"style":664},"language-python shiki shiki-themes github-dark github-dark github-light","import asyncio\nimport os\n\nfrom utcp.utcp_client import UtcpClient\n\nasync def main():\n    key = os.environ['UNIFIED_API_KEY']  # a workspace API key or a connection-scoped token\n    client = await UtcpClient.create(config={\n        # The manual is named \"unified\", so the variable is unified_UNIFIED_API_KEY\n        'variables': {'unified_UNIFIED_API_KEY': key},\n        'manual_call_templates': [{\n            'name': 'unified',\n            'call_template_type': 'http',\n            'http_method': 'GET',\n            'url': 'https:\u002F\u002Fapi.unified.to\u002Futcp?connection=\u003CCONNECTION_ID>&permissions=crm_contact_read',\n            'auth': {\n                'auth_type': 'api_key',\n                'api_key': 'Bearer ${UNIFIED_API_KEY}',\n                'var_name': 'Authorization',\n                'location': 'header',\n            },\n        }],\n    })\n\n    tools = await client.search_tools('list contacts', limit=5)\n    print([t.name for t in tools])\n\n    # Tool names are prefixed with the manual name. Arguments go under \"arguments\".\n    result = await client.call_tool('unified.list_crm_contacts', {'arguments': {'limit': 10}})\n    print(result)\n\nasyncio.run(main())\n",[26,691,692,702,710,717,731,736,751,773,796,802,817,826,841,854,867,880,889,902,922,935,948,954,960,966,971,1001,1022,1027,1033,1068,1076,1081],{"__ignoreMap":664},[668,693,694,698],{"class":670,"line":671},[668,695,697],{"class":696},"s6ubI","import",[668,699,701],{"class":700},"sAvwS"," asyncio\n",[668,703,705,707],{"class":670,"line":704},2,[668,706,697],{"class":696},[668,708,709],{"class":700}," os\n",[668,711,713],{"class":670,"line":712},3,[668,714,716],{"emptyLinePlaceholder":715},true,"\n",[668,718,720,723,726,728],{"class":670,"line":719},4,[668,721,722],{"class":696},"from",[668,724,725],{"class":700}," utcp.utcp_client ",[668,727,697],{"class":696},[668,729,730],{"class":700}," UtcpClient\n",[668,732,734],{"class":670,"line":733},5,[668,735,716],{"emptyLinePlaceholder":715},[668,737,739,742,745,748],{"class":670,"line":738},6,[668,740,741],{"class":696},"async",[668,743,744],{"class":696}," def",[668,746,747],{"class":674}," main",[668,749,750],{"class":700},"():\n",[668,752,754,757,760,763,766,769],{"class":670,"line":753},7,[668,755,756],{"class":700},"    key ",[668,758,759],{"class":696},"=",[668,761,762],{"class":700}," os.environ[",[668,764,765],{"class":678},"'UNIFIED_API_KEY'",[668,767,768],{"class":700},"]  ",[668,770,772],{"class":771},"sxXm1","# a workspace API key or a connection-scoped token\n",[668,774,776,779,781,784,787,791,793],{"class":670,"line":775},8,[668,777,778],{"class":700},"    client ",[668,780,759],{"class":696},[668,782,783],{"class":696}," await",[668,785,786],{"class":700}," UtcpClient.create(",[668,788,790],{"class":789},"sAzo5","config",[668,792,759],{"class":696},[668,794,795],{"class":700},"{\n",[668,797,799],{"class":670,"line":798},9,[668,800,801],{"class":771},"        # The manual is named \"unified\", so the variable is unified_UNIFIED_API_KEY\n",[668,803,805,808,811,814],{"class":670,"line":804},10,[668,806,807],{"class":678},"        'variables'",[668,809,810],{"class":700},": {",[668,812,813],{"class":678},"'unified_UNIFIED_API_KEY'",[668,815,816],{"class":700},": key},\n",[668,818,820,823],{"class":670,"line":819},11,[668,821,822],{"class":678},"        'manual_call_templates'",[668,824,825],{"class":700},": [{\n",[668,827,829,832,835,838],{"class":670,"line":828},12,[668,830,831],{"class":678},"            'name'",[668,833,834],{"class":700},": ",[668,836,837],{"class":678},"'unified'",[668,839,840],{"class":700},",\n",[668,842,844,847,849,852],{"class":670,"line":843},13,[668,845,846],{"class":678},"            'call_template_type'",[668,848,834],{"class":700},[668,850,851],{"class":678},"'http'",[668,853,840],{"class":700},[668,855,857,860,862,865],{"class":670,"line":856},14,[668,858,859],{"class":678},"            'http_method'",[668,861,834],{"class":700},[668,863,864],{"class":678},"'GET'",[668,866,840],{"class":700},[668,868,870,873,875,878],{"class":670,"line":869},15,[668,871,872],{"class":678},"            'url'",[668,874,834],{"class":700},[668,876,877],{"class":678},"'https:\u002F\u002Fapi.unified.to\u002Futcp?connection=\u003CCONNECTION_ID>&permissions=crm_contact_read'",[668,879,840],{"class":700},[668,881,883,886],{"class":670,"line":882},16,[668,884,885],{"class":678},"            'auth'",[668,887,888],{"class":700},": {\n",[668,890,892,895,897,900],{"class":670,"line":891},17,[668,893,894],{"class":678},"                'auth_type'",[668,896,834],{"class":700},[668,898,899],{"class":678},"'api_key'",[668,901,840],{"class":700},[668,903,905,908,910,913,917,920],{"class":670,"line":904},18,[668,906,907],{"class":678},"                'api_key'",[668,909,834],{"class":700},[668,911,912],{"class":678},"'Bearer $",[668,914,916],{"class":915},"sXWYR","{UNIFIED_API_KEY}",[668,918,919],{"class":678},"'",[668,921,840],{"class":700},[668,923,925,928,930,933],{"class":670,"line":924},19,[668,926,927],{"class":678},"                'var_name'",[668,929,834],{"class":700},[668,931,932],{"class":678},"'Authorization'",[668,934,840],{"class":700},[668,936,938,941,943,946],{"class":670,"line":937},20,[668,939,940],{"class":678},"                'location'",[668,942,834],{"class":700},[668,944,945],{"class":678},"'header'",[668,947,840],{"class":700},[668,949,951],{"class":670,"line":950},21,[668,952,953],{"class":700},"            },\n",[668,955,957],{"class":670,"line":956},22,[668,958,959],{"class":700},"        }],\n",[668,961,963],{"class":670,"line":962},23,[668,964,965],{"class":700},"    })\n",[668,967,969],{"class":670,"line":968},24,[668,970,716],{"emptyLinePlaceholder":715},[668,972,974,977,979,981,984,987,990,993,995,998],{"class":670,"line":973},25,[668,975,976],{"class":700},"    tools ",[668,978,759],{"class":696},[668,980,783],{"class":696},[668,982,983],{"class":700}," client.search_tools(",[668,985,986],{"class":678},"'list contacts'",[668,988,989],{"class":700},", ",[668,991,992],{"class":789},"limit",[668,994,759],{"class":696},[668,996,997],{"class":915},"5",[668,999,1000],{"class":700},")\n",[668,1002,1004,1007,1010,1013,1016,1019],{"class":670,"line":1003},26,[668,1005,1006],{"class":915},"    print",[668,1008,1009],{"class":700},"([t.name ",[668,1011,1012],{"class":696},"for",[668,1014,1015],{"class":700}," t ",[668,1017,1018],{"class":696},"in",[668,1020,1021],{"class":700}," tools])\n",[668,1023,1025],{"class":670,"line":1024},27,[668,1026,716],{"emptyLinePlaceholder":715},[668,1028,1030],{"class":670,"line":1029},28,[668,1031,1032],{"class":771},"    # Tool names are prefixed with the manual name. Arguments go under \"arguments\".\n",[668,1034,1036,1039,1041,1043,1046,1049,1052,1055,1057,1060,1062,1065],{"class":670,"line":1035},29,[668,1037,1038],{"class":700},"    result ",[668,1040,759],{"class":696},[668,1042,783],{"class":696},[668,1044,1045],{"class":700}," client.call_tool(",[668,1047,1048],{"class":678},"'unified.list_crm_contacts'",[668,1050,1051],{"class":700},", {",[668,1053,1054],{"class":678},"'arguments'",[668,1056,810],{"class":700},[668,1058,1059],{"class":678},"'limit'",[668,1061,834],{"class":700},[668,1063,1064],{"class":915},"10",[668,1066,1067],{"class":700},"}})\n",[668,1069,1071,1073],{"class":670,"line":1070},30,[668,1072,1006],{"class":915},[668,1074,1075],{"class":700},"(result)\n",[668,1077,1079],{"class":670,"line":1078},31,[668,1080,716],{"emptyLinePlaceholder":715},[668,1082,1084],{"class":670,"line":1083},32,[668,1085,1086],{"class":700},"asyncio.run(main())\n",[15,1088,58,1089,1092],{},[26,1090,1091],{},"auth"," on the manual template authenticates the request for the manual itself. The tools in the manual carry their own auth.",[52,1094,1096],{"id":1095},"typescript","TypeScript",[659,1098,1100],{"className":661,"code":1099,"language":663,"meta":664,"style":664},"npm install @utcp\u002Fsdk @utcp\u002Fhttp\n",[26,1101,1102],{"__ignoreMap":664},[668,1103,1104,1107,1109,1112],{"class":670,"line":671},[668,1105,1106],{"class":674},"npm",[668,1108,679],{"class":678},[668,1110,1111],{"class":678}," @utcp\u002Fsdk",[668,1113,1114],{"class":678}," @utcp\u002Fhttp\n",[659,1116,1119],{"className":1117,"code":1118,"language":1095,"meta":664,"style":664},"language-typescript shiki shiki-themes github-dark github-dark github-light","import { UtcpClient } from '@utcp\u002Fsdk';\nimport { HttpCallTemplateSerializer } from '@utcp\u002Fhttp';\n\nconst manual = new HttpCallTemplateSerializer().validateDict({\n    name: 'unified',\n    call_template_type: 'http',\n    http_method: 'GET',\n    url: 'https:\u002F\u002Fapi.unified.to\u002Futcp?connection=\u003CCONNECTION_ID>&permissions=crm_contact_read',\n    auth: {\n        auth_type: 'api_key',\n        api_key: 'Bearer ${UNIFIED_API_KEY}',\n        var_name: 'Authorization',\n        location: 'header',\n    },\n});\n\nconst client = await UtcpClient.create(process.cwd(), {\n    manual_call_templates: [manual],\n    \u002F\u002F The manual is named \"unified\", so the variable is unified_UNIFIED_API_KEY\n    variables: { unified_UNIFIED_API_KEY: process.env.UNIFIED_API_KEY! },\n});\n\nconst tools = await client.searchTools('list contacts', 5);\nconsole.log(tools.map((t) => t.name));\n\nconst result = await client.callTool('unified.list_crm_contacts', { arguments: { limit: 10 } });\nconsole.log(result);\n\nawait client.close();\n",[26,1120,1121,1136,1150,1154,1180,1189,1198,1207,1216,1221,1230,1240,1249,1258,1263,1268,1272,1298,1303,1308,1322,1326,1330,1359,1388,1392,1420,1429,1433],{"__ignoreMap":664},[668,1122,1123,1125,1128,1130,1133],{"class":670,"line":671},[668,1124,697],{"class":696},[668,1126,1127],{"class":700}," { UtcpClient } ",[668,1129,722],{"class":696},[668,1131,1132],{"class":678}," '@utcp\u002Fsdk'",[668,1134,1135],{"class":700},";\n",[668,1137,1138,1140,1143,1145,1148],{"class":670,"line":704},[668,1139,697],{"class":696},[668,1141,1142],{"class":700}," { HttpCallTemplateSerializer } ",[668,1144,722],{"class":696},[668,1146,1147],{"class":678}," '@utcp\u002Fhttp'",[668,1149,1135],{"class":700},[668,1151,1152],{"class":670,"line":712},[668,1153,716],{"emptyLinePlaceholder":715},[668,1155,1156,1159,1162,1165,1168,1171,1174,1177],{"class":670,"line":719},[668,1157,1158],{"class":696},"const",[668,1160,1161],{"class":915}," manual",[668,1163,1164],{"class":696}," =",[668,1166,1167],{"class":696}," new",[668,1169,1170],{"class":674}," HttpCallTemplateSerializer",[668,1172,1173],{"class":700},"().",[668,1175,1176],{"class":674},"validateDict",[668,1178,1179],{"class":700},"({\n",[668,1181,1182,1185,1187],{"class":670,"line":733},[668,1183,1184],{"class":700},"    name: ",[668,1186,837],{"class":678},[668,1188,840],{"class":700},[668,1190,1191,1194,1196],{"class":670,"line":738},[668,1192,1193],{"class":700},"    call_template_type: ",[668,1195,851],{"class":678},[668,1197,840],{"class":700},[668,1199,1200,1203,1205],{"class":670,"line":753},[668,1201,1202],{"class":700},"    http_method: ",[668,1204,864],{"class":678},[668,1206,840],{"class":700},[668,1208,1209,1212,1214],{"class":670,"line":775},[668,1210,1211],{"class":700},"    url: ",[668,1213,877],{"class":678},[668,1215,840],{"class":700},[668,1217,1218],{"class":670,"line":798},[668,1219,1220],{"class":700},"    auth: {\n",[668,1222,1223,1226,1228],{"class":670,"line":804},[668,1224,1225],{"class":700},"        auth_type: ",[668,1227,899],{"class":678},[668,1229,840],{"class":700},[668,1231,1232,1235,1238],{"class":670,"line":819},[668,1233,1234],{"class":700},"        api_key: ",[668,1236,1237],{"class":678},"'Bearer ${UNIFIED_API_KEY}'",[668,1239,840],{"class":700},[668,1241,1242,1245,1247],{"class":670,"line":828},[668,1243,1244],{"class":700},"        var_name: ",[668,1246,932],{"class":678},[668,1248,840],{"class":700},[668,1250,1251,1254,1256],{"class":670,"line":843},[668,1252,1253],{"class":700},"        location: ",[668,1255,945],{"class":678},[668,1257,840],{"class":700},[668,1259,1260],{"class":670,"line":856},[668,1261,1262],{"class":700},"    },\n",[668,1264,1265],{"class":670,"line":869},[668,1266,1267],{"class":700},"});\n",[668,1269,1270],{"class":670,"line":882},[668,1271,716],{"emptyLinePlaceholder":715},[668,1273,1274,1276,1279,1281,1283,1286,1289,1292,1295],{"class":670,"line":891},[668,1275,1158],{"class":696},[668,1277,1278],{"class":915}," client",[668,1280,1164],{"class":696},[668,1282,783],{"class":696},[668,1284,1285],{"class":700}," UtcpClient.",[668,1287,1288],{"class":674},"create",[668,1290,1291],{"class":700},"(process.",[668,1293,1294],{"class":674},"cwd",[668,1296,1297],{"class":700},"(), {\n",[668,1299,1300],{"class":670,"line":904},[668,1301,1302],{"class":700},"    manual_call_templates: [manual],\n",[668,1304,1305],{"class":670,"line":924},[668,1306,1307],{"class":771},"    \u002F\u002F The manual is named \"unified\", so the variable is unified_UNIFIED_API_KEY\n",[668,1309,1310,1313,1316,1319],{"class":670,"line":937},[668,1311,1312],{"class":700},"    variables: { unified_UNIFIED_API_KEY: process.env.",[668,1314,1315],{"class":915},"UNIFIED_API_KEY",[668,1317,1318],{"class":696},"!",[668,1320,1321],{"class":700}," },\n",[668,1323,1324],{"class":670,"line":950},[668,1325,1267],{"class":700},[668,1327,1328],{"class":670,"line":956},[668,1329,716],{"emptyLinePlaceholder":715},[668,1331,1332,1334,1337,1339,1341,1344,1347,1350,1352,1354,1356],{"class":670,"line":962},[668,1333,1158],{"class":696},[668,1335,1336],{"class":915}," tools",[668,1338,1164],{"class":696},[668,1340,783],{"class":696},[668,1342,1343],{"class":700}," client.",[668,1345,1346],{"class":674},"searchTools",[668,1348,1349],{"class":700},"(",[668,1351,986],{"class":678},[668,1353,989],{"class":700},[668,1355,997],{"class":915},[668,1357,1358],{"class":700},");\n",[668,1360,1361,1364,1367,1370,1373,1376,1379,1382,1385],{"class":670,"line":968},[668,1362,1363],{"class":700},"console.",[668,1365,1366],{"class":674},"log",[668,1368,1369],{"class":700},"(tools.",[668,1371,1372],{"class":674},"map",[668,1374,1375],{"class":700},"((",[668,1377,1378],{"class":789},"t",[668,1380,1381],{"class":700},") ",[668,1383,1384],{"class":696},"=>",[668,1386,1387],{"class":700}," t.name));\n",[668,1389,1390],{"class":670,"line":973},[668,1391,716],{"emptyLinePlaceholder":715},[668,1393,1394,1396,1399,1401,1403,1405,1408,1410,1412,1415,1417],{"class":670,"line":1003},[668,1395,1158],{"class":696},[668,1397,1398],{"class":915}," result",[668,1400,1164],{"class":696},[668,1402,783],{"class":696},[668,1404,1343],{"class":700},[668,1406,1407],{"class":674},"callTool",[668,1409,1349],{"class":700},[668,1411,1048],{"class":678},[668,1413,1414],{"class":700},", { arguments: { limit: ",[668,1416,1064],{"class":915},[668,1418,1419],{"class":700}," } });\n",[668,1421,1422,1424,1426],{"class":670,"line":1024},[668,1423,1363],{"class":700},[668,1425,1366],{"class":674},[668,1427,1428],{"class":700},"(result);\n",[668,1430,1431],{"class":670,"line":1029},[668,1432,716],{"emptyLinePlaceholder":715},[668,1434,1435,1438,1440,1443],{"class":670,"line":1035},[668,1436,1437],{"class":696},"await",[668,1439,1343],{"class":700},[668,1441,1442],{"class":674},"close",[668,1444,1445],{"class":700},"();\n",[52,1447,288],{"id":1448},"mcp-clients",[15,1450,1451,1452,1455,1456,1459],{},"An MCP client can already use Unified directly through the ",[19,1453,34],{"href":167,"rel":1454},[23],", which also gives it MCP Events and Agent Skills. Use the UTCP-MCP bridge only if you already manage your tools through UTCP. Add the manual template above to the bridge's ",[26,1457,1458],{},".utcp_config.json",", then add the bridge to your MCP client:",[659,1461,1465],{"className":1462,"code":1463,"language":1464,"meta":664,"style":664},"language-json shiki shiki-themes github-dark github-dark github-light","{\n    \"mcpServers\": {\n        \"utcp\": {\n            \"command\": \"npx\",\n            \"args\": [\"@utcp\u002Fmcp-bridge\"],\n            \"env\": { \"UTCP_CONFIG_FILE\": \"\u002Fpath\u002Fto\u002F.utcp_config.json\" }\n        }\n    }\n}\n","json",[26,1466,1467,1471,1478,1485,1497,1511,1530,1535,1540],{"__ignoreMap":664},[668,1468,1469],{"class":670,"line":671},[668,1470,795],{"class":700},[668,1472,1473,1476],{"class":670,"line":704},[668,1474,1475],{"class":915},"    \"mcpServers\"",[668,1477,888],{"class":700},[668,1479,1480,1483],{"class":670,"line":712},[668,1481,1482],{"class":915},"        \"utcp\"",[668,1484,888],{"class":700},[668,1486,1487,1490,1492,1495],{"class":670,"line":719},[668,1488,1489],{"class":915},"            \"command\"",[668,1491,834],{"class":700},[668,1493,1494],{"class":678},"\"npx\"",[668,1496,840],{"class":700},[668,1498,1499,1502,1505,1508],{"class":670,"line":733},[668,1500,1501],{"class":915},"            \"args\"",[668,1503,1504],{"class":700},": [",[668,1506,1507],{"class":678},"\"@utcp\u002Fmcp-bridge\"",[668,1509,1510],{"class":700},"],\n",[668,1512,1513,1516,1519,1522,1524,1527],{"class":670,"line":738},[668,1514,1515],{"class":915},"            \"env\"",[668,1517,1518],{"class":700},": { ",[668,1520,1521],{"class":915},"\"UTCP_CONFIG_FILE\"",[668,1523,834],{"class":700},[668,1525,1526],{"class":678},"\"\u002Fpath\u002Fto\u002F.utcp_config.json\"",[668,1528,1529],{"class":700}," }\n",[668,1531,1532],{"class":670,"line":753},[668,1533,1534],{"class":700},"        }\n",[668,1536,1537],{"class":670,"line":775},[668,1538,1539],{"class":700},"    }\n",[668,1541,1542],{"class":670,"line":798},[668,1543,1544],{"class":700},"}\n",[52,1546,1548],{"id":1547},"reference","Reference",[495,1550,1552],{"id":1551},"get-utcp","GET \u002Futcp",[15,1554,1555],{},"Returns a UTCP manual:",[659,1557,1562],{"className":1558,"code":1560,"language":1561},[1559],"language-text","{\n    utcp_version: string;\n    manual_version: string;\n    tools: {\n        name: string;                  \u002F\u002F the tool ID, eg. list_crm_contacts\n        description: string;\n        inputs: JSON-schema;           \u002F\u002F { arguments: { ...the tool's parameters } }\n        outputs?: JSON-schema;         \u002F\u002F the shape of a successful result\n        tags: string[];                \u002F\u002F category, object, operation, read-only \u002F destructive\n        tool_call_template: {\n            call_template_type: 'http';\n            http_method: 'POST';\n            url: string;               \u002F\u002F \u003Chost>\u002Ftools\u002F\u003Cname>\u002Fcall?\u003Cyour URL parameters>&format=utcp\n            content_type: 'application\u002Fjson';\n            body_field: 'arguments';\n            auth: { auth_type: 'api_key'; api_key: 'Bearer ${UNIFIED_API_KEY}'; var_name: 'Authorization'; location: 'header' };\n        };\n    }[];\n}\n","text",[26,1563,1560],{"__ignoreMap":664},[79,1565,1566,1576],{},[82,1567,1568],{},[85,1569,1570,1573],{},[88,1571,1572],{},"Status",[88,1574,1575],{},"When",[96,1577,1578,1588,1598],{},[85,1579,1580,1585],{},[101,1581,1582],{},[26,1583,1584],{},"401",[101,1586,1587],{},"A credential was presented but is not valid",[85,1589,1590,1595],{},[101,1591,1592],{},[26,1593,1594],{},"403",[101,1596,1597],{},"The request's IP address is not on the workspace's allowlist",[85,1599,1600,1605],{},[101,1601,1602],{},[26,1603,1604],{},"404",[101,1606,1607,1609],{},[26,1608,632],{}," names an unknown integration",[495,1611,1613],{"id":1612},"tool-calls","Tool calls",[15,1615,1616,1617,1620,1621,1626],{},"Each tool is called with ",[26,1618,1619],{},"POST \u002Ftools\u002F{id}\u002Fcall?…&format=utcp",", the ",[19,1622,1625],{"href":1623,"rel":1624},"https:\u002F\u002Fdocs.unified.to\u002Fmcp\u002Fadditional-api-endpoints#post-toolsidcall",[23],"Call Tool"," endpoint.",[1628,1629,1630,1648,1670],"ul",{},[1631,1632,1633,1639,1640,1643,1644,1647],"li",{},[42,1634,1635,1636,50],{},"Arguments are nested under ",[26,1637,1638],{},"arguments"," UTCP sends one input as the request body (the template's ",[26,1641,1642],{},"body_field",") and every other input as a query parameter, so the tool's parameters are grouped into that one input. Pass ",[26,1645,1646],{},"{ arguments: { … } }",", not the parameters at the top level.",[1631,1649,1650,1653,1654,1657,1658,1661,1662,1665,1666,1669],{},[42,1651,1652],{},"A successful call returns the result itself",", described by the tool's ",[26,1655,1656],{},"outputs",". A list result is wrapped as ",[26,1659,1660],{},"{ results: [...] }",". With ",[26,1663,1664],{},"format=utcp"," there is no ",[26,1667,1668],{},"{ content, structuredContent }"," envelope.",[1631,1671,1672,251,1675,989,1678,989,1680,989,1682,989,1684,1687,1688,1691],{},[42,1673,1674],{},"A failed call returns an error status",[26,1676,1677],{},"400",[26,1679,1584],{},[26,1681,1594],{},[26,1683,1604],{},[26,1685,1686],{},"429",", or the integration API's own status) with an ",[26,1689,1690],{},"isError"," body. UTCP clients raise these as errors.",[15,1693,1694],{},"Each tool call counts as 1 API request on your plan.",[1696,1697,1698],"style",{},"html pre.shiki code .s5n6i, html code.shiki .s5n6i{--shiki-default:#B392F0;--shiki-dark:#B392F0;--shiki-light:#6F42C1}html pre.shiki code .s4Y1p, html code.shiki .s4Y1p{--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-light:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .s6ubI, html code.shiki .s6ubI{--shiki-default:#F97583;--shiki-dark:#F97583;--shiki-light:#D73A49}html pre.shiki code .sAvwS, html code.shiki .sAvwS{--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8;--shiki-light:#24292E}html pre.shiki code .sxXm1, html code.shiki .sxXm1{--shiki-default:#6A737D;--shiki-dark:#6A737D;--shiki-light:#6A737D}html pre.shiki code .sAzo5, html code.shiki .sAzo5{--shiki-default:#FFAB70;--shiki-dark:#FFAB70;--shiki-light:#E36209}html pre.shiki code .sXWYR, html code.shiki .sXWYR{--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-light:#005CC5}",{"title":664,"searchDepth":704,"depth":704,"links":1700},[1701,1702,1703,1707,1708,1709,1710],{"id":54,"depth":704,"text":55},{"id":183,"depth":704,"text":184},{"id":371,"depth":704,"text":372,"children":1704},[1705,1706],{"id":497,"depth":712,"text":498},{"id":531,"depth":712,"text":532},{"id":657,"depth":704,"text":206},{"id":1095,"depth":704,"text":1096},{"id":1448,"depth":704,"text":288},{"id":1547,"depth":704,"text":1548,"children":1711},[1712,1713],{"id":1551,"depth":712,"text":1552},{"id":1612,"depth":712,"text":1613},"Unified.to publishes its tools as a UTCP (Universal Tool Calling Protocol) manual at \u002Futcp. A UTCP client reads the manual and then calls the Unified API directly over HTTP. The tools, permissions and billing are the same as on the MCP server, but UTCP is a separate protocol: there is no MCP connection involved.","md",{},{"title":6,"description":1714},"ARwEE9LeOVNkZNZiQLY3t0DtpocWE_41JSKmPemuQA8",1793726961985]