@kynver-app/mcp-agent-os 0.3.119 → 0.3.120

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{McpServer as A}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as P}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as o}from"zod";var C="https://www.kynver.com/api/agent-connector/v1";function y(t=process.env){let e=t.KYNVER_AGENT_CONNECTOR_KEY?.trim();if(!e||!/^kyc_[A-Za-z0-9_-]{43}$/.test(e))return{error:"KYNVER_AGENT_CONNECTOR_KEY is missing or not a Kynver connection key (it starts with kyc_). Copy it from Kynver \u2192 Connect."};let r=(t.KYNVER_AGENT_CONNECTOR_URL?.trim()||C).replace(/\/+$/,"");return!/^https:\/\//.test(r)&&!/^http:\/\/localhost(:\d+)?\//.test(`${r}/`)?{error:"KYNVER_AGENT_CONNECTOR_URL must be an https address."}:{baseUrl:r,key:e}}var l=class extends Error{constructor(r,a){super(a);this.status=r;this.name="AgentChatError"}status};async function f(t,e,r,a,c=fetch){if(!r.startsWith("/")||r.includes(".."))throw new l(400,"bad path");let s=await c(`${t.baseUrl}${r}`,{method:e,headers:{authorization:`Bearer ${t.key}`,...a===void 0?{}:{"content-type":"application/json"}},body:a===void 0?void 0:JSON.stringify(a),redirect:"error",signal:AbortSignal.timeout(45e3)}),d=await s.json().catch(()=>({}));if(!s.ok)throw new l(s.status,typeof d.error=="string"?d.error:`request failed (${s.status})`);return d}async function v(t,e,r=fetch){let a=new URLSearchParams({name:e.name,...e.mime?{mime:e.mime}:{}}),c=await r(`${t.baseUrl}/files?${a}`,{method:"POST",headers:{authorization:`Bearer ${t.key}`,"content-type":"application/octet-stream"},body:Buffer.from(e.contentBase64,"base64"),redirect:"error",signal:AbortSignal.timeout(45e3*2)}),s=await c.json().catch(()=>({}));if(!c.ok)throw new l(c.status,typeof s.error=="string"?s.error:`upload failed (${c.status})`);return s}import{existsSync as T,readFileSync as S}from"node:fs";import{dirname as h,join as k}from"node:path";import{fileURLToPath as w}from"node:url";function b(t){let e=h(w(t));for(let r=0;r<6;r+=1){if(T(k(e,"package.json")))return e;let a=h(e);if(a===e)break;e=a}throw new Error(`package.json not found above ${h(w(t))}`)}function E(t,e){let r=k(b(t),"package.json"),c=JSON.parse(S(r,"utf8"))[e];if(typeof c!="string"||!c.trim())throw new Error(`Missing package.json ${e} at ${r}`);return c}function u(t=import.meta.url){return E(t,"version")}function R(t){return t.some(e=>e==="--version"||e==="-v")}function O(t,e){console.log(e?`${e} ${t}`:t),process.exit(0)}function _(t,e=import.meta.url,r){return R(t)?(O(u(e),r),!0):!1}var $=u(import.meta.url);function N(t){return{content:[{type:"text",text:JSON.stringify(t)}],structuredContent:t}}function x(t){return{content:[{type:"text",text:t}],isError:!0}}function U(t=process.env,e=fetch){let r=new A({name:"kynver-agent-chat",version:$},{capabilities:{tools:{}}}),a=y(t),c="error"in a?null:a,s=async n=>{if(!c)return x("error"in a?a.error:"Not configured.");try{return N(await n(c))}catch(i){return x(i instanceof Error?i.message:"That didn't work.")}},d=(n,i,m,I)=>f(n,i,m,I,e),p=r.registerTool.bind(r),g=o.guid().optional().describe("conversationId from the message you are answering. Omit for the chat's open conversation.");return p("kynver_chat_wait_for_messages",{description:"Wait (up to 25 seconds) for new messages from the person you chat with in Kynver. Returns { events, cursor }. Call it again with the cursor you got back; start with since=0. Each event has text, messageId, conversationId, attachments and quote. Calling this marks you connected.",inputSchema:{since:o.number().int().min(0).optional(),waitSeconds:o.number().int().min(0).max(25).optional(),limit:o.number().int().min(1).max(50).optional()}},async n=>s(i=>d(i,"GET",`/messages?${new URLSearchParams({since:String(n.since??0),wait:String(n.waitSeconds??25),limit:String(n.limit??20)})}`))),p("kynver_chat_reply",{description:"Send your reply in the Kynver chat (Markdown). Pass replyTo (the messageId you answer) and conversationId from the event. idempotencyKey makes a retry safe: the same key never posts twice. Optionally attach files made with kynver_chat_upload_file.",inputSchema:{text:o.string().max(32e3).optional(),conversationId:g,replyTo:o.string().min(1).max(80).optional(),idempotencyKey:o.string().min(4).max(100).optional(),fileIds:o.array(o.guid()).max(10).optional(),notify:o.boolean().optional().describe("Buzz the person's phone. Default true.")}},async n=>s(i=>d(i,"POST","/messages",{text:n.text??"",...n.conversationId?{conversationId:n.conversationId}:{},...n.replyTo?{replyTo:n.replyTo,idempotencyKey:n.idempotencyKey??`reply-${n.replyTo}`}:n.idempotencyKey?{idempotencyKey:n.idempotencyKey}:{},attachments:(n.fileIds??[]).map(m=>({fileId:m})),...n.notify===void 0?{}:{notify:n.notify}}))),p("kynver_chat_stream",{description:"Stream one reply that grows. First call without messageId and with text: it appears in the chat now and you get a messageId. Then call with that messageId and append (more text) as often as you like; finish with done=true (that is when the badge and phone notification fire).",inputSchema:{messageId:o.string().min(1).max(80).optional(),text:o.string().max(32e3).optional(),append:o.string().max(32e3).optional(),done:o.boolean().optional(),conversationId:g,replyTo:o.string().min(1).max(80).optional()}},async n=>s(i=>{if(!n.messageId)return d(i,"POST","/messages",{text:n.text??"\u2026",stream:!0,...n.conversationId?{conversationId:n.conversationId}:{},...n.replyTo?{replyTo:n.replyTo}:{}});let m=n.conversationId?`?conversationId=${encodeURIComponent(n.conversationId)}`:"";return d(i,"PATCH",`/messages/${encodeURIComponent(n.messageId)}${m}`,{...n.append!==void 0?{append:n.append}:n.text!==void 0?{text:n.text}:{},done:n.done===!0})})),p("kynver_chat_typing",{description:'Show that you are typing or working (for about 25 seconds). Optional label in plain words, e.g. "searching the web".',inputSchema:{label:o.string().min(1).max(40).optional(),conversationId:g}},async n=>s(i=>d(i,"POST","/typing",{...n.label?{label:n.label}:{},...n.conversationId?{conversationId:n.conversationId}:{}}))),p("kynver_chat_upload_file",{description:"Upload a file (up to 20 MB) and get a fileId to attach with kynver_chat_reply.",inputSchema:{name:o.string().min(1).max(200),contentBase64:o.string().min(1),mime:o.string().max(120).optional()}},async n=>s(i=>v(i,n,e))),p("kynver_chat_ask",{description:"Ask the person a question with buttons. They tap one; read the answer with kynver_chat_get_answer (or it also arrives as their next message). Button text is what they send back.",inputSchema:{id:o.string().min(1).max(80).describe("A short id you choose, e.g. pick-1."),question:o.string().min(1).max(500),options:o.array(o.string().min(1).max(40)).min(1).max(6),conversationId:g}},async n=>s(i=>d(i,"POST","/messages",{text:"",ask:{id:n.id,question:n.question,options:n.options.map(m=>({label:m}))},...n.conversationId?{conversationId:n.conversationId}:{}}))),p("kynver_chat_get_answer",{description:"Has the person answered a question you asked with kynver_chat_ask? Returns { answered, answer }.",inputSchema:{id:o.string().min(1).max(80),conversationId:g}},async n=>s(i=>d(i,"GET",`/asks/${encodeURIComponent(n.id)}${n.conversationId?`?conversationId=${encodeURIComponent(n.conversationId)}`:""}`))),p("kynver_chat_history",{description:"Recent messages of this chat, oldest first, so you can answer in context.",inputSchema:{limit:o.number().int().min(1).max(80).optional(),conversationId:g}},async n=>s(i=>d(i,"GET",`/history?${new URLSearchParams({limit:String(n.limit??40),...n.conversationId?{conversationId:n.conversationId}:{}})}`))),r}var K=process.argv[1]?.endsWith("agent-chat.js")||process.argv[1]?.endsWith("agent-chat.ts");K&&(_(process.argv.slice(2),import.meta.url,"kynver-agent-chat-mcp"),await U().connect(new P));export{U as createAgentChatServer};
2
+ import{McpServer as A}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as P}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as o}from"zod";var C="https://www.kynver.com/api/agent-connector/v1";function y(t=process.env){let n=t.KYNVER_AGENT_CONNECTOR_KEY?.trim();if(!n||!/^kyc_[A-Za-z0-9_-]{43}$/.test(n))return{error:"KYNVER_AGENT_CONNECTOR_KEY is missing or not a Kynver connection key (it starts with kyc_). Copy it from Kynver \u2192 Connect."};let r=(t.KYNVER_AGENT_CONNECTOR_URL?.trim()||C).replace(/\/+$/,"");return!/^https:\/\//.test(r)&&!/^http:\/\/localhost(:\d+)?\//.test(`${r}/`)?{error:"KYNVER_AGENT_CONNECTOR_URL must be an https address."}:{baseUrl:r,key:n}}var l=class extends Error{constructor(r,a){super(a);this.status=r;this.name="AgentChatError"}status};async function f(t,n,r,a,c=fetch){if(!r.startsWith("/")||r.includes(".."))throw new l(400,"bad path");let s=await c(`${t.baseUrl}${r}`,{method:n,headers:{authorization:`Bearer ${t.key}`,...a===void 0?{}:{"content-type":"application/json"}},body:a===void 0?void 0:JSON.stringify(a),redirect:"error",signal:AbortSignal.timeout(45e3)}),d=await s.json().catch(()=>({}));if(!s.ok)throw new l(s.status,typeof d.error=="string"?d.error:`request failed (${s.status})`);return d}async function v(t,n,r=fetch){let a=new URLSearchParams({name:n.name,...n.mime?{mime:n.mime}:{}}),c=await r(`${t.baseUrl}/files?${a}`,{method:"POST",headers:{authorization:`Bearer ${t.key}`,"content-type":"application/octet-stream"},body:Buffer.from(n.contentBase64,"base64"),redirect:"error",signal:AbortSignal.timeout(45e3*2)}),s=await c.json().catch(()=>({}));if(!c.ok)throw new l(c.status,typeof s.error=="string"?s.error:`upload failed (${c.status})`);return s}import{existsSync as T,readFileSync as S}from"node:fs";import{dirname as h,join as k}from"node:path";import{fileURLToPath as w}from"node:url";function b(t){let n=h(w(t));for(let r=0;r<6;r+=1){if(T(k(n,"package.json")))return n;let a=h(n);if(a===n)break;n=a}throw new Error(`package.json not found above ${h(w(t))}`)}function E(t,n){let r=k(b(t),"package.json"),c=JSON.parse(S(r,"utf8"))[n];if(typeof c!="string"||!c.trim())throw new Error(`Missing package.json ${n} at ${r}`);return c}function u(t=import.meta.url){return E(t,"version")}function R(t){return t.some(n=>n==="--version"||n==="-v")}function O(t,n){console.log(n?`${n} ${t}`:t),process.exit(0)}function x(t,n=import.meta.url,r){return R(t)?(O(u(n),r),!0):!1}var $=u(import.meta.url);function N(t){return{content:[{type:"text",text:JSON.stringify(t)}],structuredContent:t}}function _(t){return{content:[{type:"text",text:t}],isError:!0}}function U(t=process.env,n=fetch){let r=new A({name:"kynver-agent-chat",version:$},{capabilities:{tools:{}}}),a=y(t),c="error"in a?null:a,s=async e=>{if(!c)return _("error"in a?a.error:"Not configured.");try{return N(await e(c))}catch(i){return _(i instanceof Error?i.message:"That didn't work.")}},d=(e,i,g,I)=>f(e,i,g,I,n),p=r.registerTool.bind(r),m=o.guid().optional().describe("conversationId from the message you are answering. Omit for the chat's open conversation.");return p("kynver_chat_wait_for_messages",{description:"Wait (up to 25 seconds) for new messages from the person you chat with in Kynver. Returns { events, cursor }. Call it again with the cursor you got back; start with since=0. Each event has text, messageId, conversationId, attachments and quote. Calling this marks you connected.",inputSchema:{since:o.number().int().min(0).optional(),waitSeconds:o.number().int().min(0).max(25).optional(),limit:o.number().int().min(1).max(50).optional()}},async e=>s(i=>d(i,"GET",`/messages?${new URLSearchParams({since:String(e.since??0),wait:String(e.waitSeconds??25),limit:String(e.limit??20)})}`))),p("kynver_chat_reply",{description:"Send your reply in the Kynver chat (Markdown). Pass replyTo (the messageId you answer) and conversationId from the event. idempotencyKey makes a retry safe: the same key never posts twice. Optionally attach files made with kynver_chat_upload_file.",inputSchema:{text:o.string().max(32e3).optional(),conversationId:m,replyTo:o.string().min(1).max(80).optional(),idempotencyKey:o.string().min(4).max(100).optional(),fileIds:o.array(o.guid()).max(10).optional(),notify:o.boolean().optional().describe("Buzz the person's phone. Default true."),final:o.boolean().optional().describe("Default true: this answers the message (replyTo, else the oldest one you haven't answered) and the chat stops showing you as working; their next queued message is sent to you. false: an update while you keep working.")}},async e=>s(i=>d(i,"POST","/messages",{text:e.text??"",...e.conversationId?{conversationId:e.conversationId}:{},...e.replyTo?{replyTo:e.replyTo,idempotencyKey:e.idempotencyKey??`reply-${e.replyTo}`}:e.idempotencyKey?{idempotencyKey:e.idempotencyKey}:{},attachments:(e.fileIds??[]).map(g=>({fileId:g})),...e.notify===void 0?{}:{notify:e.notify},...e.final===void 0?{}:{final:e.final}}))),p("kynver_chat_stream",{description:"Stream one reply that grows. First call without messageId and with text: it appears in the chat now and you get a messageId. Then call with that messageId and append (more text) as often as you like; finish with done=true (that is when the badge and phone notification fire).",inputSchema:{messageId:o.string().min(1).max(80).optional(),text:o.string().max(32e3).optional(),append:o.string().max(32e3).optional(),done:o.boolean().optional(),conversationId:m,replyTo:o.string().min(1).max(80).optional()}},async e=>s(i=>{if(!e.messageId)return d(i,"POST","/messages",{text:e.text??"\u2026",stream:!0,...e.conversationId?{conversationId:e.conversationId}:{},...e.replyTo?{replyTo:e.replyTo}:{}});let g=e.conversationId?`?conversationId=${encodeURIComponent(e.conversationId)}`:"";return d(i,"PATCH",`/messages/${encodeURIComponent(e.messageId)}${g}`,{...e.append!==void 0?{append:e.append}:e.text!==void 0?{text:e.text}:{},done:e.done===!0})})),p("kynver_chat_typing",{description:'Show that you are typing or working (for about 25 seconds). Optional label in plain words, e.g. "searching the web".',inputSchema:{label:o.string().min(1).max(40).optional(),conversationId:m}},async e=>s(i=>d(i,"POST","/typing",{...e.label?{label:e.label}:{},...e.conversationId?{conversationId:e.conversationId}:{}}))),p("kynver_chat_upload_file",{description:"Upload a file (up to 20 MB) and get a fileId to attach with kynver_chat_reply.",inputSchema:{name:o.string().min(1).max(200),contentBase64:o.string().min(1),mime:o.string().max(120).optional()}},async e=>s(i=>v(i,e,n))),p("kynver_chat_ask",{description:"Ask the person a question with buttons. They tap one; read the answer with kynver_chat_get_answer (or it also arrives as their next message). Button text is what they send back.",inputSchema:{id:o.string().min(1).max(80).describe("A short id you choose, e.g. pick-1."),question:o.string().min(1).max(500),options:o.array(o.string().min(1).max(40)).min(1).max(6),conversationId:m}},async e=>s(i=>d(i,"POST","/messages",{text:"",ask:{id:e.id,question:e.question,options:e.options.map(g=>({label:g}))},...e.conversationId?{conversationId:e.conversationId}:{}}))),p("kynver_chat_get_answer",{description:"Has the person answered a question you asked with kynver_chat_ask? Returns { answered, answer }.",inputSchema:{id:o.string().min(1).max(80),conversationId:m}},async e=>s(i=>d(i,"GET",`/asks/${encodeURIComponent(e.id)}${e.conversationId?`?conversationId=${encodeURIComponent(e.conversationId)}`:""}`))),p("kynver_chat_history",{description:"Recent messages of this chat, oldest first, so you can answer in context.",inputSchema:{limit:o.number().int().min(1).max(80).optional(),conversationId:m}},async e=>s(i=>d(i,"GET",`/history?${new URLSearchParams({limit:String(e.limit??40),...e.conversationId?{conversationId:e.conversationId}:{}})}`))),r}var K=process.argv[1]?.endsWith("agent-chat.js")||process.argv[1]?.endsWith("agent-chat.ts");K&&(x(process.argv.slice(2),import.meta.url,"kynver-agent-chat-mcp"),await U().connect(new P));export{U as createAgentChatServer};