healthy-companion 1.0.3
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/.github/workflows/npm.yml +19 -0
- package/AGENTS.md +34 -0
- package/eslint.config.cjs +62 -0
- package/package.json +15 -0
- package/server.js +27 -0
- package/tools/todo.js +50 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: Publish on NPM registry
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ['main']
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v2
|
|
12
|
+
- uses: actions/setup-node@v2
|
|
13
|
+
with:
|
|
14
|
+
node-version: 24.x
|
|
15
|
+
registry-url: https://registry.npmjs.org/
|
|
16
|
+
# - run: npm install
|
|
17
|
+
- run: npm publish --access public
|
|
18
|
+
env:
|
|
19
|
+
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Core Rules
|
|
2
|
+
|
|
3
|
+
The following principles and rules **MUST** always be followed, under all circumstances:
|
|
4
|
+
|
|
5
|
+
## I. Lightweight Architecture
|
|
6
|
+
|
|
7
|
+
Code, logic, and architecture **MUST** remain lightweight. Dependencies **MUST** be minimal and purposeful.
|
|
8
|
+
|
|
9
|
+
## II. Simple and Minimalist Implementation
|
|
10
|
+
|
|
11
|
+
Code **MUST** be simple, clear, and readable—prefer straightforward, maintainable solutions over complex ones.
|
|
12
|
+
Keep the codebase minimal: avoid clever or tricky one-liners in favor of clarity.
|
|
13
|
+
Keep the code clean: avoid duplication.
|
|
14
|
+
|
|
15
|
+
## III. Developer-Centric Documentation
|
|
16
|
+
|
|
17
|
+
All documentation **MUST** be developer-focused, with clear, concise technical explanations. Quickstart guides **MUST** enable local setup in under 5 minutes.
|
|
18
|
+
Keep the documentation minimal, and avoid duplication.
|
|
19
|
+
|
|
20
|
+
## IV. Change Management
|
|
21
|
+
|
|
22
|
+
When changes are made, update the version in `package.json` and revise documentation (Markdown files) to reflect them.
|
|
23
|
+
|
|
24
|
+
## V. Comprehensive Change Analysis
|
|
25
|
+
|
|
26
|
+
When implementing or fixing code, always verify correctness by analyzing related files and dependencies. But never write or run tests.
|
|
27
|
+
|
|
28
|
+
## VI. Docs-Code Consistency
|
|
29
|
+
|
|
30
|
+
Documentation and code **MUST** stay in sync:
|
|
31
|
+
|
|
32
|
+
- Update docs whenever code changes and vice versa if docs are updated.
|
|
33
|
+
- Docs must match real behaviors.
|
|
34
|
+
- Any mismatch between docs and code should be addressed.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module.exports = [
|
|
2
|
+
{
|
|
3
|
+
languageOptions: {
|
|
4
|
+
parserOptions: {
|
|
5
|
+
ecmaVersion: 13,
|
|
6
|
+
impliedStrict: true,
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
rules: {
|
|
10
|
+
"no-trailing-spaces": "error",
|
|
11
|
+
"linebreak-style": ["error", "unix"],
|
|
12
|
+
"quotes": ["error", "double"],
|
|
13
|
+
"one-var": ["error", "never"],
|
|
14
|
+
"brace-style": ["error", "allman", { allowSingleLine: true }],
|
|
15
|
+
"space-before-blocks": "warn",
|
|
16
|
+
"func-call-spacing": "error",
|
|
17
|
+
"space-before-function-paren": "error",
|
|
18
|
+
"space-in-parens": ["error", "always", { exceptions: ["{}"] }],
|
|
19
|
+
"keyword-spacing": "error",
|
|
20
|
+
"comma-spacing": "error",
|
|
21
|
+
"space-unary-ops": "error",
|
|
22
|
+
"block-spacing": "error",
|
|
23
|
+
"arrow-spacing": "error",
|
|
24
|
+
"key-spacing": "error",
|
|
25
|
+
"comma-style": "error",
|
|
26
|
+
"space-infix-ops": "error",
|
|
27
|
+
"array-bracket-spacing": "error",
|
|
28
|
+
"object-curly-spacing": ["error", "always"],
|
|
29
|
+
"no-multi-spaces": "error",
|
|
30
|
+
"operator-linebreak": "error",
|
|
31
|
+
"function-paren-newline": "warn",
|
|
32
|
+
"arrow-body-style": ["error", "always"],
|
|
33
|
+
"no-template-curly-in-string": "error",
|
|
34
|
+
"no-new-object": "error",
|
|
35
|
+
"no-extra-parens": ["error", "all", { conditionalAssign: false }],
|
|
36
|
+
"no-empty-function": "error",
|
|
37
|
+
"no-empty": ["warn", { allowEmptyCatch: true }],
|
|
38
|
+
"no-eq-null": "error",
|
|
39
|
+
"no-extra-bind": "error",
|
|
40
|
+
"no-self-compare": "error",
|
|
41
|
+
"no-useless-call": "error",
|
|
42
|
+
"no-undefined": "error",
|
|
43
|
+
"no-array-constructor": "error",
|
|
44
|
+
"prefer-destructuring": ["error",
|
|
45
|
+
{
|
|
46
|
+
VariableDeclarator: { array: false, object: true }, AssignmentExpression: { array: false, object: false } }, { enforceForRenamedProperties: false
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"object-shorthand": "warn",
|
|
50
|
+
"prefer-spread": "warn",
|
|
51
|
+
"prefer-template": "warn",
|
|
52
|
+
"no-loop-func": "warn",
|
|
53
|
+
"prefer-rest-params": "warn",
|
|
54
|
+
"no-new-func": "warn",
|
|
55
|
+
"no-unneeded-ternary": "warn",
|
|
56
|
+
"no-process-exit": "off",
|
|
57
|
+
"require-await": "warn",
|
|
58
|
+
"indent": ["error", "tab", { MemberExpression: 0 }],
|
|
59
|
+
"no-tabs": 0,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "healthy-companion",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A healthy companion MCP server with todo and water tracking",
|
|
6
|
+
"main": "server.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "node server.js"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
12
|
+
"eslint": "^9.39.2",
|
|
13
|
+
"zod": "^4.3.6"
|
|
14
|
+
}
|
|
15
|
+
}
|
package/server.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { registerTodoTools } from "./tools/todo.js";
|
|
4
|
+
|
|
5
|
+
const server = new McpServer({
|
|
6
|
+
name: "healthy-companion",
|
|
7
|
+
version: "1.0.0",
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
registerTodoTools( server );
|
|
11
|
+
const transport = new StdioServerTransport();
|
|
12
|
+
|
|
13
|
+
void async function main ()
|
|
14
|
+
{
|
|
15
|
+
try
|
|
16
|
+
{
|
|
17
|
+
const transport = new StdioServerTransport();
|
|
18
|
+
await server.connect( transport );
|
|
19
|
+
console.warn( "MCP server is running..." );
|
|
20
|
+
}
|
|
21
|
+
catch ( error )
|
|
22
|
+
{
|
|
23
|
+
console.error( "Server error:", error );
|
|
24
|
+
process.exit( 1 );
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
}()
|
package/tools/todo.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
const todos = [];
|
|
4
|
+
|
|
5
|
+
export function registerTodoTools ( server )
|
|
6
|
+
{
|
|
7
|
+
server.tool(
|
|
8
|
+
"todo_add",
|
|
9
|
+
"Add a TODO item",
|
|
10
|
+
{ item: z.string().describe( "The text of the todo item" ) },
|
|
11
|
+
async ({ item }) =>
|
|
12
|
+
{
|
|
13
|
+
todos.push( item );
|
|
14
|
+
return {
|
|
15
|
+
content: [{ type: "text", text: `Added TODO: "${item}"` }],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
server.tool(
|
|
21
|
+
"todo_list",
|
|
22
|
+
"List all TODO items",
|
|
23
|
+
{},
|
|
24
|
+
async () =>
|
|
25
|
+
{
|
|
26
|
+
if ( todos.length === 0 )
|
|
27
|
+
{
|
|
28
|
+
return { content: [{ type: "text", text: "No TODO items." }] };
|
|
29
|
+
}
|
|
30
|
+
const lines = todos.map( ( todo, idx ) => { return `${idx + 1}. ${todo}` }).join( "\n" );
|
|
31
|
+
return { content: [{ type: "text", text: lines }] };
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
server.tool(
|
|
36
|
+
"todo_remove",
|
|
37
|
+
"Remove a TODO item by its number",
|
|
38
|
+
{ index: z.number().int().positive().describe( "1-based index of the item to remove" ) },
|
|
39
|
+
async ({ index }) =>
|
|
40
|
+
{
|
|
41
|
+
const i = index - 1;
|
|
42
|
+
if ( i < 0 || i >= todos.length )
|
|
43
|
+
{
|
|
44
|
+
return { content: [{ type: "text", text: `Invalid index: ${index}` }] };
|
|
45
|
+
}
|
|
46
|
+
const removed = todos.splice( i, 1 )[0];
|
|
47
|
+
return { content: [{ type: "text", text: `Removed TODO: "${removed}"` }] };
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
}
|