katyayani-core-mcp 1.0.0

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 ADDED
@@ -0,0 +1,56 @@
1
+ # katyayani-core-mcp
2
+
3
+ MCP server for **Katyayani Core** (Customer Engagement Platform). Add it to Claude / Cursor / any MCP
4
+ client and ask anything about the platform — live data **and** how the SDKs work.
5
+
6
+ ## What you can ask
7
+
8
+ - **Live data** (needs a token): "How many installs from google-play last 30 days?", "Top referrers",
9
+ "Revenue by source", "Show the acquisition funnel", "Find user 6261414316".
10
+ - **How-to / docs** (no token needed): "How do I add referral sharing?", "How to set user attributes?",
11
+ "What does trackAttribution do?", "How to install the Flutter SDK?", "Does the RN SDK auto-ask push permission?"
12
+
13
+ ## Tools
14
+
15
+ | Tool | Purpose |
16
+ |------|---------|
17
+ | `kc_docs` | Platform + SDK knowledge (install, identify/attributes, events, attribution, referral, push). Works with **no token**. |
18
+ | `kc_get` | Read live dashboard data (users, attribution, revenue, referrals, funnels…). Needs `KC_TOKEN`. |
19
+ | `kc_action` | Write actions (create smart link, send message…). Needs `KC_TOKEN`. |
20
+
21
+ ## Install (Claude Code)
22
+
23
+ ```bash
24
+ claude mcp add katyayani-core \
25
+ -e KC_TOKEN=<shared-token> \
26
+ -e KC_TENANT_ID=<project-tenant-id> \
27
+ -- npx -y katyayani-core-mcp
28
+ ```
29
+
30
+ - **`KC_TOKEN`** — the shared access token (ask whoever gave you this MCP). Omit it and only `kc_docs` works.
31
+ - **`KC_TENANT_ID`** *(optional)* — scopes all data to one project. Omit → the API's default project.
32
+ - **`KC_API_BASE`** *(optional)* — defaults to `https://8.231.80.238.nip.io`.
33
+
34
+ ### Cursor / other clients (`mcp.json`)
35
+
36
+ ```json
37
+ {
38
+ "mcpServers": {
39
+ "katyayani-core": {
40
+ "command": "npx",
41
+ "args": ["-y", "katyayani-core-mcp"],
42
+ "env": { "KC_TOKEN": "<shared-token>", "KC_TENANT_ID": "<tenant-id>" }
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ ## Security
49
+
50
+ `KC_TOKEN` is a full-access dashboard token — share it only with people you trust. It is **never** baked
51
+ into this package; it is read from your MCP config at runtime. `kc_docs` needs no token, so you can share
52
+ the docs experience openly.
53
+
54
+ ## License
55
+
56
+ MIT
package/dist/api.js ADDED
@@ -0,0 +1,66 @@
1
+ // Thin authenticated HTTP layer for the Katyayani Core dashboard API.
2
+ // Auth = a single shared token sent as `Authorization: Bearer <token>`.
3
+ // The default is the platform's static dashboard key; override via KC_TOKEN.
4
+ // KC_TENANT_ID (optional) scopes every call to one project via the x-tenant-id header.
5
+ export const API_BASE = (process.env.KC_API_BASE || 'https://8.231.80.238.nip.io').replace(/\/$/, '');
6
+ // Shared access token — provided by whoever shares this MCP, via the KC_TOKEN env.
7
+ // Intentionally NOT hardcoded so the secret never ships inside the published package.
8
+ const TOKEN = process.env.KC_TOKEN || '';
9
+ export const TENANT_ID = process.env.KC_TENANT_ID || '';
10
+ const NO_TOKEN_MSG = 'No access token set. Live data (kc_get / kc_action) needs the shared KC_TOKEN env var — ' +
11
+ 'ask whoever shared this MCP for the token, then set KC_TOKEN in your MCP config. ' +
12
+ 'Docs (kc_docs) work without a token.';
13
+ function headers(extra = {}) {
14
+ const h = { authorization: `Bearer ${TOKEN}`, ...extra };
15
+ if (TENANT_ID)
16
+ h['x-tenant-id'] = TENANT_ID;
17
+ return h;
18
+ }
19
+ function normalizePath(path) {
20
+ let p = path.trim();
21
+ if (!p.startsWith('/'))
22
+ p = '/' + p;
23
+ // Be forgiving: allow callers to pass "attribution/overview" or "/v1/..." etc.
24
+ if (!p.startsWith('/v1/') && !p.startsWith('/health') && p !== '/') {
25
+ p = '/v1' + p;
26
+ }
27
+ return p;
28
+ }
29
+ async function parse(res) {
30
+ const text = await res.text();
31
+ try {
32
+ return JSON.parse(text);
33
+ }
34
+ catch {
35
+ return { _status: res.status, _nonJson: text.slice(0, 2000) };
36
+ }
37
+ }
38
+ export async function apiGet(path, params) {
39
+ if (!TOKEN)
40
+ return { error: NO_TOKEN_MSG };
41
+ const p = normalizePath(path);
42
+ let qs = '';
43
+ if (params && Object.keys(params).length) {
44
+ const usp = new URLSearchParams();
45
+ for (const [k, v] of Object.entries(params)) {
46
+ if (v !== undefined && v !== null && v !== '')
47
+ usp.set(k, String(v));
48
+ }
49
+ const s = usp.toString();
50
+ if (s)
51
+ qs = '?' + s;
52
+ }
53
+ const res = await fetch(`${API_BASE}${p}${qs}`, { headers: headers() });
54
+ return parse(res);
55
+ }
56
+ export async function apiSend(method, path, body) {
57
+ if (!TOKEN)
58
+ return { error: NO_TOKEN_MSG };
59
+ const p = normalizePath(path);
60
+ const res = await fetch(`${API_BASE}${p}`, {
61
+ method: method.toUpperCase(),
62
+ headers: headers({ 'content-type': 'application/json' }),
63
+ body: body != null ? JSON.stringify(body) : undefined,
64
+ });
65
+ return parse(res);
66
+ }
package/dist/docs.js ADDED
@@ -0,0 +1,180 @@
1
+ // Bundled Katyayani Core knowledge base. `kc_docs` returns the whole thing (or
2
+ // the sections matching a topic) so anyone can ask how the platform / SDKs work.
3
+ const SECTIONS = [
4
+ {
5
+ title: 'Overview — what Katyayani Core is',
6
+ keywords: ['overview', 'what', 'platform', 'intro', 'about', 'architecture'],
7
+ body: `Katyayani Core is a multi-tenant Customer Engagement Platform (Netcore / Linkrunner-style MMP).
8
+ It ingests events from client SDKs (Flutter, React Native, Web), stitches user identities, tracks
9
+ install attribution + revenue, sends push notifications, and shows everything in a dashboard.
10
+
11
+ - API base URL: https://8.231.80.238.nip.io
12
+ - Dashboard: same host (Next.js). Events/analytics, Attribution, Users, Push, Segments, Workflows.
13
+ - Each project = a "tenant"/app with its own SDK API key (nc_live_...). A key maps to a tenant.
14
+ - Data stores: Postgres (users, links, config), ClickHouse (events, attribution funnel, revenue).`,
15
+ },
16
+ {
17
+ title: 'SDK install — Flutter, React Native, Web',
18
+ keywords: ['install', 'setup', 'sdk', 'init', 'flutter', 'react native', 'rn', 'web', 'add'],
19
+ body: `All three SDKs talk to the same backend and share the same core API (init, identify, track,
20
+ attribution, capturePayment, referral).
21
+
22
+ FLUTTER (package "katyayani_core" on pub.dev, latest 1.10.0):
23
+ dependencies: katyayani_core: ^1.10.0
24
+ await KatyayaniCore.init(
25
+ siteId: 'nc_live_...', // your SDK API key
26
+ apiBase: 'https://8.231.80.238.nip.io',
27
+ enablePush: false, // set true ONLY if Firebase is configured (see Push section)
28
+ );
29
+
30
+ REACT NATIVE (package "katyayani-core-react-native" on npm, latest 1.3.0):
31
+ npm i katyayani-core-react-native
32
+ await KatyayaniCore.init({ siteId: 'nc_live_...', apiBase: 'https://8.231.80.238.nip.io', enablePush: true });
33
+
34
+ WEB (self-hosted script, global nc(...)):
35
+ <script src="https://8.231.80.238.nip.io/nc.min.js"></script>
36
+ nc('init', { siteId: 'nc_live_...', apiBase: 'https://8.231.80.238.nip.io' });`,
37
+ },
38
+ {
39
+ title: 'Identify & user attributes (traits)',
40
+ keywords: ['identify', 'user', 'attribute', 'attributes', 'traits', 'profile', 'phone', 'email', 'set user'],
41
+ body: `Set user attributes with identify() — there is NO separate setUserAttributes method.
42
+
43
+ KatyayaniCore.identify('+916261414316', traits: {
44
+ 'phone': '+916261414316', // recognized → phone column (needed for Users search)
45
+ 'email': 'ram@x.com', // recognized → email column
46
+ 'name': 'Ram Kumar', // auto-split into firstName/lastName
47
+ 'city': 'Indore', // any other key → customAttributes (JSON)
48
+ 'plan': 'premium',
49
+ });
50
+
51
+ Recognized keys → dedicated columns: phone, email, name, firstName, lastName, $timezone, $locale.
52
+ Everything else → customAttributes.
53
+
54
+ MERGE BEHAVIOR (important):
55
+ - Standard fields (phone/email/name...) are PATCHED — fields you don't send stay unchanged.
56
+ - customAttributes are REPLACED as a whole IF you send any custom key. Sending {plan:'gold'} alone
57
+ wipes other custom attributes. To update one custom attribute safely, resend all custom attributes,
58
+ OR ask the platform team to enable server-side jsonb merge.
59
+ - Sending only standard fields (no custom keys) leaves customAttributes untouched.
60
+
61
+ You MUST call identify() to create a profile — init() alone keeps the user anonymous.
62
+ Use a stable, readable userId (e.g. '+916261414316'), not a random UUID.`,
63
+ },
64
+ {
65
+ title: 'Events & ecommerce tracking',
66
+ keywords: ['event', 'track', 'ecommerce', 'purchase', 'screen', 'analytics', 'ga4'],
67
+ body: `Track custom events and GA4-aligned ecommerce events.
68
+
69
+ KatyayaniCore.track('button_clicked', properties: {'screen': 'home'});
70
+ KatyayaniCore.screenView('ProductPage');
71
+
72
+ Ecommerce convenience methods (GA4 payload {currency, value, transaction_id, items:[...]}):
73
+ viewItem, addToCart, removeFromCart, viewCart, beginCheckout, addPaymentInfo, purchase, refund.
74
+ e.g. KatyayaniCore.purchase({'currency':'INR','value':1499,'transaction_id':'ORD1','items':[...]});
75
+
76
+ track() = product analytics (Analytics/Events pages). For revenue attribution use capturePayment().`,
77
+ },
78
+ {
79
+ title: 'Attribution & sources (Meta / Google / organic / referral)',
80
+ keywords: ['attribution', 'source', 'meta', 'google', 'ads', 'organic', 'utm', 'install', 'trackattribution', 'funnel', 'campaign', 'smart link'],
81
+ body: `WHICH source a user came from (meta / google / organic / referral) is detected AUTOMATICALLY at
82
+ install time (resolveInstall runs on init). You never pass the source manually. It is derived from:
83
+ 1. A Katyayani Core smart link click (/l/<code>) — the link's configured source wins.
84
+ 2. Play Store install referrer UTM (utm_source=google, etc.).
85
+ 3. Click→install fingerprint match (iOS / no referrer).
86
+ 4. Nothing matched → 'organic'.
87
+
88
+ To make Meta/Google show up (not 'organic'), drive installs through a KC SMART LINK per channel
89
+ (Dashboard → Attribution → Links, source=meta/google) OR a Play Store URL tagged with utm_source.
90
+
91
+ FUNNEL milestones are MANUAL — the SDK can't know when "signup" happens:
92
+ KatyayaniCore.trackAttribution('signup'); // ties this conversion to the user's acquired source
93
+ KatyayaniCore.capturePayment(1499, orderId: 'ORD1'); // ties revenue to source
94
+
95
+ Funnel: click → install → signup (trackAttribution) → purchase (capturePayment). The built-in funnel
96
+ only counts type 'signup' as the signup step; other trackAttribution types are stored as raw events.
97
+
98
+ Manual vs auto:
99
+ AUTO → source detection, referral tracking, install/click counts.
100
+ MANUAL→ trackAttribution('signup'), capturePayment(amount), putting a KC smart link in your ads.`,
101
+ },
102
+ {
103
+ title: 'Referral sharing (referral attribution)',
104
+ keywords: ['referral', 'refer', 'share', 'generatereferrallink', 'onreferral', 'confirmreferral', 'referrer', 'referee', 'invite'],
105
+ body: `Referral flow (app shares a link → new user installs → code auto-links → backend tracks who
106
+ referred whom). Available in all 3 SDKs (Flutter 1.10.0, RN 1.3.0, Web).
107
+
108
+ 1) SHARE side (referrer):
109
+ final url = await KatyayaniCore.generateReferralLink(
110
+ myReferralCode, // your app's own code (app-provided)
111
+ referrerId: currentUserId, // sharer's userId
112
+ deepLinkPath: '/referral',
113
+ androidStoreUrl: 'https://play.google.com/store/apps/details?id=com.mymali', // REQUIRED
114
+ );
115
+ Share.share('Join with my code: $url');
116
+
117
+ 2) INSTALL side (new user) — auto:
118
+ KatyayaniCore.onReferral((code, params) {
119
+ referralField.text = code; // auto-fill; params['referrerId'] = who referred
120
+ });
121
+
122
+ 3) After signup (authoritative):
123
+ KatyayaniCore.confirmReferral(code, referrerId: params['referrerId']);
124
+
125
+ The SDK DELIVERS the code + referrerId to your app via onReferral; YOUR app decides which field to
126
+ fill and how to reward. Reward crediting lives in your backend. Backend records referrer↔referee in
127
+ the referrals table; report at GET /v1/attribution/referrals.
128
+ androidStoreUrl (Play details URL) must be passed once so the install-referrer flow works.
129
+
130
+ Web commands: nc('referral.generate', opts, cb); nc('referral.on', cb); nc('referral.confirm', code, opts); nc('referral.getCode', cb).`,
131
+ },
132
+ {
133
+ title: 'Push notifications',
134
+ keywords: ['push', 'notification', 'fcm', 'firebase', 'permission', 'enablepush', 'sticky', 'timer'],
135
+ body: `Push uses Firebase (FCM). enablePush defaults to TRUE in the Flutter SDK.
136
+
137
+ - No Firebase in the project? Set enablePush: false — otherwise init() can throw (no default Firebase
138
+ app) and the WHOLE SDK fails to initialize (events/attribution/referral stop too).
139
+ - With enablePush:true the SDK registers the FCM token on startup WITHOUT asking permission
140
+ (getToken works without display permission). It does NOT auto-request notification permission.
141
+ - To actually show notifications, call KatyayaniCore.requestPushPermission() at a good moment
142
+ (needed for Android 13+ POST_NOTIFICATIONS and iOS). Add POST_NOTIFICATIONS to AndroidManifest.
143
+ - Rich push (sticky / timer / custom sound) is Flutter-only. RN has FCM topics + host-rendered nudges.
144
+ - Per-project FCM service account is configured in Dashboard → Settings → App Management.`,
145
+ },
146
+ {
147
+ title: 'Dashboard data & API endpoints',
148
+ keywords: ['dashboard', 'api', 'endpoint', 'data', 'report', 'query', 'revenue', 'users', 'segments', 'workflows'],
149
+ body: `Read data via kc_get (GET) and mutate via kc_action (POST/PATCH/DELETE). Common paths:
150
+
151
+ Attribution: /v1/attribution/overview?days=30 (per-source clicks/installs/revenue/ROAS)
152
+ /v1/attribution/funnel?days=30
153
+ /v1/attribution/timeseries?days=30
154
+ /v1/attribution/referrals?limit=100 (top referrers)
155
+ /v1/attribution/links (smart links)
156
+ Users: /v1/users?page=1&limit=20&search=... ; /v1/users/:id ; /v1/users/:id/activity
157
+ Analytics: /v1/analytics/overview?days=30 ; /v1/analytics/revenue ; /v1/analytics/events/summary
158
+ /v1/analytics/retention ; /v1/analytics/rfm ; /v1/analytics/geo ; /v1/analytics/devices
159
+ Apps/config: /v1/apps ; /v1/settings/api-keys ; /v1/segments ; /v1/workflows ; /v1/nudges
160
+ Actions: POST /v1/attribution/links (create smart link),
161
+ POST /v1/attribution/referral/generate (needs SDK key, not dashboard token),
162
+ POST /v1/transactional/email|sms|whatsapp, POST /v1/segments.
163
+
164
+ Auth is a single shared Bearer token; KC_TENANT_ID scopes to one project.`,
165
+ },
166
+ ];
167
+ const TOC = SECTIONS.map((s, i) => ` ${i + 1}. ${s.title}`).join('\n');
168
+ export function getDocs(topic) {
169
+ const header = `# Katyayani Core — Knowledge Base\n\nSections:\n${TOC}\n\n(Call kc_docs with a topic keyword to narrow, or no topic for everything.)\n\n`;
170
+ if (topic && topic.trim()) {
171
+ const q = topic.toLowerCase();
172
+ const matched = SECTIONS.filter((s) => s.title.toLowerCase().includes(q) ||
173
+ s.keywords.some((k) => q.includes(k) || k.includes(q)));
174
+ if (matched.length) {
175
+ return matched.map((s) => `## ${s.title}\n\n${s.body}`).join('\n\n---\n\n');
176
+ }
177
+ // No match → fall through to full docs so the caller still gets an answer.
178
+ }
179
+ return header + SECTIONS.map((s) => `## ${s.title}\n\n${s.body}`).join('\n\n---\n\n');
180
+ }
package/dist/index.js ADDED
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
5
+ import { apiGet, apiSend, API_BASE, TENANT_ID } from './api.js';
6
+ import { getDocs } from './docs.js';
7
+ const ENDPOINT_CATALOG = `
8
+ Common GET paths (pass as "path", optional "params"):
9
+ Attribution:
10
+ /v1/attribution/overview params: {days} → per-source clicks/installs/users/orders/revenue/ROAS
11
+ /v1/attribution/funnel params: {days} → click→install→signup→purchase counts
12
+ /v1/attribution/timeseries params: {days} → daily revenue/installs by source
13
+ /v1/attribution/referrals params: {limit} → top referrers + totals (who referred whom)
14
+ /v1/attribution/links → all smart links
15
+ /v1/attribution/links/:id/stats params:{days}
16
+ Users:
17
+ /v1/users params: {page,limit,search}
18
+ /v1/users/:id → single profile (traits, customAttributes)
19
+ /v1/users/:id/activity → recent events
20
+ Analytics:
21
+ /v1/analytics/overview params: {days}
22
+ /v1/analytics/revenue params: {days}
23
+ /v1/analytics/events/summary params: {days}
24
+ /v1/analytics/retention | /rfm | /geo | /devices | /realtime | /fatigue
25
+ Config:
26
+ /v1/apps → projects + SDK keys
27
+ /v1/segments | /v1/workflows | /v1/nudges | /v1/settings/api-keys
28
+ `;
29
+ const tools = [
30
+ {
31
+ name: 'kc_docs',
32
+ description: 'Explain how Katyayani Core (the Customer Engagement Platform) and its SDKs work. Covers: platform overview, SDK install (Flutter/React Native/Web), identify & user attributes, events/ecommerce, attribution & sources (Meta/Google/organic/referral), the referral system, push notifications, and the dashboard/API. Use for any "how do I / what is / how does X work" question. Pass an optional topic keyword to focus.',
33
+ inputSchema: {
34
+ type: 'object',
35
+ properties: {
36
+ topic: {
37
+ type: 'string',
38
+ description: 'Optional keyword to focus the docs, e.g. "referral", "attribution", "user attributes", "push", "install", "events". Omit to get everything.',
39
+ },
40
+ },
41
+ },
42
+ },
43
+ {
44
+ name: 'kc_get',
45
+ description: 'Read LIVE data from the Katyayani Core dashboard API (GET). Use for any question about real numbers: users, events, attribution by source, revenue/ROAS, funnels, referrals, segments, workflows, etc. Provide the API "path" and optional "params". ' +
46
+ ENDPOINT_CATALOG,
47
+ inputSchema: {
48
+ type: 'object',
49
+ properties: {
50
+ path: {
51
+ type: 'string',
52
+ description: 'API path, e.g. "/v1/attribution/overview" or "/v1/users". "/v1" is added if you omit it.',
53
+ },
54
+ params: {
55
+ type: 'object',
56
+ description: 'Optional query params, e.g. {"days": 30} or {"search": "6261", "limit": 20}.',
57
+ additionalProperties: true,
58
+ },
59
+ },
60
+ required: ['path'],
61
+ },
62
+ },
63
+ {
64
+ name: 'kc_action',
65
+ description: 'Perform a WRITE action on Katyayani Core (POST/PATCH/DELETE) — e.g. create a smart link (POST /v1/attribution/links), create a segment, send a transactional message. This MUTATES data; use only when the user explicitly asks to create/update/send something. Prefer kc_get for reads.',
66
+ inputSchema: {
67
+ type: 'object',
68
+ properties: {
69
+ method: { type: 'string', enum: ['POST', 'PATCH', 'DELETE'], description: 'HTTP method (default POST).' },
70
+ path: { type: 'string', description: 'API path, e.g. "/v1/attribution/links".' },
71
+ body: { type: 'object', description: 'JSON body for the request.', additionalProperties: true },
72
+ },
73
+ required: ['path'],
74
+ },
75
+ },
76
+ ];
77
+ const server = new Server({ name: 'katyayani-core', version: '1.0.0' }, { capabilities: { tools: {} } });
78
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
79
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
80
+ const { name } = req.params;
81
+ const args = (req.params.arguments || {});
82
+ try {
83
+ if (name === 'kc_docs') {
84
+ return { content: [{ type: 'text', text: getDocs(args.topic) }] };
85
+ }
86
+ if (name === 'kc_get') {
87
+ if (!args.path)
88
+ throw new Error('path is required');
89
+ const data = await apiGet(String(args.path), args.params);
90
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
91
+ }
92
+ if (name === 'kc_action') {
93
+ if (!args.path)
94
+ throw new Error('path is required');
95
+ const data = await apiSend(String(args.method || 'POST'), String(args.path), args.body);
96
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
97
+ }
98
+ return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };
99
+ }
100
+ catch (e) {
101
+ return { content: [{ type: 'text', text: `Error: ${e?.message || String(e)}` }], isError: true };
102
+ }
103
+ });
104
+ async function main() {
105
+ const transport = new StdioServerTransport();
106
+ await server.connect(transport);
107
+ console.error(`katyayani-core MCP running → ${API_BASE}${TENANT_ID ? ` (tenant ${TENANT_ID})` : ''}`);
108
+ }
109
+ main().catch((e) => {
110
+ console.error('katyayani-core MCP failed to start:', e);
111
+ process.exit(1);
112
+ });
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "katyayani-core-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Katyayani Core (Customer Engagement Platform). Ask anything about your CEP — users, events, attribution (Meta/Google/organic/referral), revenue/ROAS, referrals, funnels — plus full SDK & platform how-to docs.",
5
+ "type": "module",
6
+ "bin": {
7
+ "katyayani-core-mcp": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "start": "node dist/index.js"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "model-context-protocol",
19
+ "katyayani-core",
20
+ "analytics",
21
+ "attribution",
22
+ "claude"
23
+ ],
24
+ "author": "Katyayani Organics",
25
+ "license": "MIT",
26
+ "dependencies": {
27
+ "@modelcontextprotocol/sdk": "^1.12.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.10.0",
31
+ "typescript": "^5.7.0"
32
+ },
33
+ "engines": {
34
+ "node": ">=18"
35
+ }
36
+ }