Sign In

@planifyapps/mcp

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@planifyapps/mcp - npm Package Compare versions

Comparing version
0.1.0
to
0.2.0
+25
-1
dist/index.js

@@ -34,3 +34,3 @@ #!/usr/bin/env node

import { z } from 'zod';
const VERSION = '0.1.0';
const VERSION = '0.2.0';
const DEFAULT_BASE = 'https://planifyapps.com/api/v1';

@@ -134,2 +134,14 @@ const API_KEY = process.env.PLANIFY_API_KEY ?? '';

});
/* ─────────────────────────────── Annotations ─────────────────────────────── */
/**
* Every tool declares whether it can change anything. Clients use this to decide
* what to run without asking — and directory review requires it — but the reason
* to get it right is that "fetch the Pinterest boards" and "publish to a real
* audience" should never look alike to something deciding whether to confirm.
*
* openWorldHint is true throughout: every tool reaches a live external service.
*/
const READS = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true };
/** Creates something, but nothing anyone can see and nothing that can't be redone. */
const WRITES = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true };
server.registerTool('planify_me', {

@@ -140,2 +152,3 @@ title: 'Planify: account and plan',

inputSchema: {},
annotations: READS,
}, async () => text(await call('GET', '/me')));

@@ -148,2 +161,3 @@ server.registerTool('planify_list_channels', {

inputSchema: {},
annotations: READS,
}, async () => text(await call('GET', '/channels')));

@@ -159,2 +173,3 @@ server.registerTool('planify_channel_settings', {

},
annotations: READS,
}, async ({ channel_id }) => text(await call('GET', `/channels/${encodeURIComponent(channel_id)}/settings`)));

@@ -172,2 +187,5 @@ server.registerTool('planify_channel_trigger', {

},
// A POST on the wire, but a lookup in effect: it fetches boards and communities
// and changes nothing. Annotated for what it does, not for its HTTP verb.
annotations: READS,
}, async ({ channel_id, method_name, data }) => text(await call('POST', `/channels/${encodeURIComponent(channel_id)}/trigger`, {

@@ -186,2 +204,3 @@ body: { method_name, data: data ?? {} },

},
annotations: READS,
}, async ({ channel_id, count, after }) => text(await call('GET', `/channels/${encodeURIComponent(channel_id)}/slot`, {

@@ -198,2 +217,3 @@ query: { count: count ? String(count) : undefined, after },

},
annotations: WRITES,
}, async ({ urls }) => text(await call('POST', '/media/from-url', { body: { urls } })));

@@ -235,2 +255,6 @@ server.registerTool('planify_create_post', {

},
// destructiveHint even though this only ever creates: with type "now" the result
// is public and irreversible, and the hint exists so a client knows to confirm.
// Annotating the common case (a draft) would hide the case that actually matters.
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
}, async (args) => {

@@ -237,0 +261,0 @@ const { idempotency_key, type, ...rest } = args;

+3
-1
{
"name": "@planifyapps/mcp",
"version": "0.1.0",
"version": "0.2.0",
"description": "Model Context Protocol server for Planify — let an AI assistant schedule and publish social posts.",
"//": "mcpName is how the MCP Registry proves this npm package belongs to the server it lists. It must stay identical to `name` in server.json.",
"mcpName": "com.planifyapps/planify",
"keywords": [

@@ -6,0 +8,0 @@ "mcp",

@@ -74,2 +74,24 @@ # @planifyapps/mcp

## Releasing
Two places have to move together. The registry lists metadata only — it fetches the
npm package and checks that its `package.json` carries an `mcpName` matching the
`name` in `server.json`. Publish to the registry before npm and it fails validation.
Bump the version in three places (`package.json`, `VERSION` in `src/index.ts`, and
both `version` fields in `server.json`), then:
```bash
npm publish --access public # npm first, always
mcp-publisher login http --domain planifyapps.com \
--private-key "$(openssl pkey -in .mcp-registry-key.pem -noout -text | grep -A3 'priv:' | tail -n +2 | tr -d ' :\n')"
mcp-publisher publish
```
Domain authentication is what lets the server be named `com.planifyapps/planify`
rather than sitting under a personal GitHub namespace. The proof is the public key
at `/.well-known/mcp-registry-auth`, served from `public/` in the web app; the
matching private key is `.mcp-registry-key.pem`, gitignored and kept out of the
repo. Lose it and you regenerate the pair and redeploy the proof file.
## Links

@@ -76,0 +98,0 @@