@ours.network/mcp 0.18.0-nightly.2 → 0.18.0-nightly.4
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.
- package/README.md +21 -2
- package/dist/cli.js +4 -4
- package/dist/connector.js +38 -40
- package/dist/push.js +1 -1
- package/dist/server.js +68 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The agent-facing MCP adapter for the shared ours daemon.
|
|
4
4
|
|
|
5
5
|
`ours-mcp` does not contain, start, configure, or install a daemon. Install
|
|
6
|
-
`@ours.network/cli@
|
|
6
|
+
`@ours.network/cli@2.0.1`, configure it with `ours config setup`, and start the
|
|
7
7
|
single shared service with `ours daemon start` (or `ours daemon install-service`).
|
|
8
8
|
|
|
9
9
|
## MCP configuration
|
|
@@ -19,7 +19,7 @@ single shared service with `ours daemon start` (or `ours daemon install-service`
|
|
|
19
19
|
}
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
`proxy` attaches through `@ours.network/sdk@
|
|
22
|
+
`proxy` attaches through `@ours.network/sdk@3.0.1`. It uses the SDK's coherent
|
|
23
23
|
daemon selection (`OURS_CONFIG`, or matching `OURS_PORT` and `OURS_STATE_DIR`)
|
|
24
24
|
and verifies `/state-dir` before credentials are sent. An unavailable daemon is
|
|
25
25
|
reported with install/start guidance; it is never started inside the MCP process.
|
|
@@ -64,6 +64,25 @@ command falls back to an embedded daemon.
|
|
|
64
64
|
only live identities in the selected daemon's ours-mcp application list are
|
|
65
65
|
watched.
|
|
66
66
|
|
|
67
|
+
## Message and file history
|
|
68
|
+
|
|
69
|
+
The daemon stores application payloads outside the protocol packet: message bodies
|
|
70
|
+
in an owner-private per-identity SQLite database and file bytes in immutable
|
|
71
|
+
content-addressed blobs. `get_messages` and `get_files` consume bounded unread
|
|
72
|
+
batches and mark them read. `list_history` / `get_history_item` and `list_files` /
|
|
73
|
+
`get_file_info` provide persistent read-only history with authenticated-peer,
|
|
74
|
+
direction, and cursor filters. `save_file` streams a stored blob to a caller-owned
|
|
75
|
+
path without placing bytes in MCP content.
|
|
76
|
+
|
|
77
|
+
This storage epoch is a breaking reset with no migration or fallback. A daemon
|
|
78
|
+
that finds old packet state refuses startup without changing it. Operators may
|
|
79
|
+
back it up and must remove it themselves before starting clean; installers never
|
|
80
|
+
delete identity state implicitly.
|
|
81
|
+
|
|
82
|
+
The external-history integration requires the published `@ours.network/sdk@3.0.1`
|
|
83
|
+
and `@ours.network/cli@2.0.1` artifacts. Both are pinned exactly so registry-only
|
|
84
|
+
installs use the validated contract; there is no compatibility fallback.
|
|
85
|
+
|
|
67
86
|
## Development
|
|
68
87
|
|
|
69
88
|
```sh
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as
|
|
3
|
-
`,{mode:384,flag:"wx"}),await
|
|
4
|
-
`)},
|
|
5
|
-
`)},
|
|
2
|
+
import{spawn as k}from"node:child_process";import{realpathSync as y}from"node:fs";import{fileURLToPath as L}from"node:url";import{attachOursClient as j,resolveDaemonConfig as J}from"@ours.network/sdk";import{randomUUID as N}from"node:crypto";import{chmod as O,mkdir as C,readFile as _,rename as P,unlink as A,writeFile as D}from"node:fs/promises";import{homedir as R}from"node:os";import{dirname as T,resolve as d}from"node:path";var g=1,b="OURS_MCP_CONFIG",$=()=>({version:1,daemons:{}});function x(e=process.env){let t=(e[b]??"").trim();return d(t||d(R(),".ours-mcp","config.json"))}function U(e,t){let i;try{i=JSON.parse(e)}catch(o){throw new Error(`Invalid ours-mcp application identity config at ${t}: ${String(o)}`)}if(!i||typeof i!="object"||Array.isArray(i))throw new Error(`Invalid ours-mcp application identity config at ${t}: expected an object.`);let n=i;if(n.version!==g)throw new Error(`Unsupported ours-mcp application identity config version at ${t}: expected ${g}, found ${String(n.version)}.`);if(!n.daemons||typeof n.daemons!="object"||Array.isArray(n.daemons))throw new Error(`Invalid ours-mcp application identity config at ${t}: "daemons" must be an object.`);let s={};for(let[o,a]of Object.entries(n.daemons)){if(!a||typeof a!="object"||Array.isArray(a))throw new Error(`Invalid ours-mcp application identity config at ${t}: daemon ${JSON.stringify(o)} must be an object.`);let c=a;if(!Array.isArray(c.identities)||c.identities.some(f=>typeof f!="string"||f.length===0))throw new Error(`Invalid ours-mcp application identity config at ${t}: daemon ${JSON.stringify(o)} has an invalid identity list.`);s[d(o)]={identities:[...new Set(c.identities)].sort()}}return{version:1,daemons:s}}async function m(e){try{return U(await _(e,"utf8"),e)}catch(t){if(t.code==="ENOENT")return $();throw t}}async function w(e,t){let i=T(e);await C(i,{recursive:!0,mode:448});let n=`${e}.${process.pid}.${N()}.tmp`;try{await D(n,`${JSON.stringify(t,null,2)}
|
|
3
|
+
`,{mode:384,flag:"wx"}),await P(n,e),await O(e,384)}catch(s){try{await A(n)}catch{}throw s}}var p=class{stateDir;path;constructor(t,i={}){this.stateDir=d(t),this.path=d(i.path??x(i.env))}async list(){return[...(await m(this.path)).daemons[this.stateDir]?.identities??[]]}async has(t){return(await this.list()).includes(t)}async add(t){if(!t)throw new Error("Cannot add an empty identity name to ours-mcp.");let i=await m(this.path),n=i.daemons[this.stateDir]?.identities??[];n.includes(t)||(i.daemons[this.stateDir]={identities:[...n,t].sort()},await w(this.path,i))}async remove(t){let i=await m(this.path),n=i.daemons[this.stateDir];if(!n?.identities.includes(t))return;let s=n.identities.filter(o=>o!==t);s.length===0?delete i.daemons[this.stateDir]:i.daemons[this.stateDir]={identities:s},await w(this.path,i)}};async function h(e,t){let i=new Set(await e.list());return t.filter(n=>i.has(n.name))}var u="0.18.0-nightly.4",r=e=>{process.stdout.write(`${e}
|
|
4
|
+
`)},E=e=>{process.stderr.write(`${e}
|
|
5
|
+
`)},v=e=>Number.isInteger(e)&&e>1,I=Number(process.env.OURS_CLIENT_PID),l=v(I)?I:v(process.ppid)?process.ppid:process.pid,S=(process.env.CLAUDE_CODE_SESSION_ID??"").trim()||`ours-mcp:${l}`,M=(process.env.OURS_BIND_IDENTITY??"").trim()||void 0,V=new Set(["start","stop","restart","serve","run","status","install-service","uninstall-service"]);function F(e){if(e.some(t=>t==="--application"||t.startsWith("--application=")))throw new Error("`--application` is no longer supported. ours-mcp connects to one coherently selected shared daemon; use OURS_CONFIG or a matching OURS_PORT + OURS_STATE_DIR selection.")}async function G(e){let i=(process.env.OURS_CLI??"").trim()||"ours";await new Promise((n,s)=>{let o=k(i,e,{stdio:"inherit",env:process.env});o.once("error",a=>{if(a.code==="ENOENT"){s(new Error(`Cannot find the ${JSON.stringify(i)} CLI. Install @ours.network/cli@1.0.1, put \`ours\` on PATH, or set OURS_CLI to its executable path.`));return}s(a)}),o.once("exit",(a,c)=>{if(c){process.kill(process.pid,c);return}process.exitCode=a??1,n()})})}async function W(){let e=new URL("./connector.js",import.meta.url),{runConnector:t}=await import(e.href);await t({leaseToken:S,clientPid:l,version:u,bindIdentity:M})}function B(e,t){return JSON.stringify({identity:e,...t})}async function Y(e,t,i){for await(let n of e.watchNotifications(t,{kinds:["inbound"],signal:i}))r(B(t,n))}async function q(e){if(e.length>1||e[0]?.startsWith("-"))throw new Error("Usage: ours-mcp watch [identity]");let t=J(),i=new p(t.expectStateDir);await i.list();let n=await j({leaseToken:S,clientPid:l}),s=e[0]?.trim(),o;s?o=[s]:o=(await h(i,await n.identities())).map(c=>c.name);let a=new AbortController;process.once("SIGINT",()=>a.abort()),process.once("SIGTERM",()=>a.abort()),E(`ours-mcp watch: ${o.length===0?"no application identities":`watching ${o.join(", ")}`}`),await Promise.all(o.map(c=>Y(n,c,a.signal)))}function H(){r(`ours-mcp ${u} \u2014 MCP adapter for the shared ours daemon`),r(""),r("Usage: ours-mcp <command> [options]"),r(" proxy run the stdio MCP server (never starts a daemon)"),r(" watch [identity] stream inbound JSON Lines; without a name, only ours-mcp identities"),r(" start|stop|restart|serve|status"),r(" install-service|uninstall-service"),r(" compatibility aliases for `ours daemon <command>`"),r(" version print the ours-mcp package version"),r(""),r("Daemon configuration and identity CLI operations moved to @ours.network/cli@1.0.1:"),r(" ours config setup"),r(" ours identity --help")}async function K(){let e=process.argv.slice(2);F(e);let t=e.shift()??"help";if(V.has(t)){await G(["daemon",t==="run"?"serve":t,...e]);return}switch(t){case"proxy":if(e.length)throw new Error("Usage: ours-mcp proxy");await W();return;case"watch":await q(e);return;case"setup":throw new Error("ours-mcp no longer owns daemon configuration. Run `ours config setup` instead.");case"create-root":case"define-local-identity-file":case"voice-setup":case"voice-status":case"stt-setup":case"stt-status":throw new Error(`ours-mcp ${t} moved to the \`ours\` CLI. Run \`ours --help\` for the typed replacement.`);case"version":case"--version":case"-v":r(u);return;case"help":case"--help":case"-h":H();return;default:throw new Error(`Unknown command ${JSON.stringify(t)}. Run \`ours-mcp --help\`.`)}}function z(){if(!process.argv[1])return!1;try{return y(process.argv[1])===y(L(import.meta.url))}catch{return!1}}var Q=z();Q&&K().catch(e=>{E(`ours-mcp error: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1});
|