@o-t-p-y/mcp 0.3.2
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/LICENSE +21 -0
- package/README.md +101 -0
- package/dist/index.d.ts +176 -0
- package/dist/index.js +404 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OTPy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# @o-t-p-y/mcp
|
|
2
|
+
|
|
3
|
+
Official Model Context Protocol (MCP) server for [OTPy.ir](https://otpy.ir) — interact with your OTPy account, inspect usage, send test codes, and manage keys directly from AI assistants.
|
|
4
|
+
|
|
5
|
+
## Two credentials
|
|
6
|
+
|
|
7
|
+
This server can use up to two different OTPy credentials, each for a different purpose:
|
|
8
|
+
|
|
9
|
+
| Credential | Env var / flag | What it's for |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| **API key** (project-scoped) | `OTPY_API_KEY` / `--api-key` | Read/write access to OTP-related endpoints: `get_usage`, `send_test_otp`, `verify_test_otp`, `get_integration_snippet`. This is the same `otpy_...` key you use to send real OTPs from your product. |
|
|
12
|
+
| **User key** (user-scoped) | `OTPY_USER_KEY` / `--user-key` | Real, server-verified scope gating for write- and billing-sensitive tools (see below). This is a separate `otpy_uk_...` secret, obtained from the **Integrate** tab on [dash.otpy.ir](https://dash.otpy.ir). |
|
|
13
|
+
|
|
14
|
+
You do not strictly need a user key to use the read-only tools (`get_usage`, `get_integration_snippet`) — only the API key is required for those. But any tool that requires the `write` or `billing` scope (see below) is denied outright if no user key is configured.
|
|
15
|
+
|
|
16
|
+
## Installation / Setup
|
|
17
|
+
|
|
18
|
+
### Cursor
|
|
19
|
+
|
|
20
|
+
Add to your `.cursor/mcp.json` or Cursor Settings → MCP:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"otpy": {
|
|
26
|
+
"command": "npx",
|
|
27
|
+
"args": ["-y", "@o-t-p-y/mcp"],
|
|
28
|
+
"env": {
|
|
29
|
+
"OTPY_API_KEY": "otpy_your_api_key_here",
|
|
30
|
+
"OTPY_USER_KEY": "otpy_uk_your_user_key_here"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Claude Desktop
|
|
38
|
+
|
|
39
|
+
Add to `claude_desktop_config.json`:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"mcpServers": {
|
|
44
|
+
"otpy": {
|
|
45
|
+
"command": "npx",
|
|
46
|
+
"args": ["-y", "@o-t-p-y/mcp"],
|
|
47
|
+
"env": {
|
|
48
|
+
"OTPY_API_KEY": "otpy_your_api_key_here",
|
|
49
|
+
"OTPY_USER_KEY": "otpy_uk_your_user_key_here"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
You can also copy the pre-configured MCP snippet directly from the **Integrate** tab on [dash.otpy.ir](https://dash.otpy.ir).
|
|
57
|
+
|
|
58
|
+
## Scope model (`user_keys`)
|
|
59
|
+
|
|
60
|
+
Every user key has exactly two independently toggleable scopes, `write` and `billing`, plus a `root` flag that is always *derived* as `write AND billing` — it is never set directly. There is no third, separately-grantable permission.
|
|
61
|
+
|
|
62
|
+
| Scope | Grants |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `write` | `send_test_otp`, `verify_test_otp`, `create_api_key` |
|
|
65
|
+
| `billing` | `get_balance`, `list_api_keys` |
|
|
66
|
+
| `root` (derived: `write` and `billing` both true) | Everything above — not a separate scope, just shorthand for "has both". |
|
|
67
|
+
|
|
68
|
+
Create a user key with the scopes you need on the **Integrate** tab of [dash.otpy.ir](https://dash.otpy.ir) (create/list/revoke and toggling `write`/`billing` all live there). The raw `otpy_uk_...` secret is shown exactly once at creation time — copy it into `OTPY_USER_KEY` immediately.
|
|
69
|
+
|
|
70
|
+
### How scope verification actually works
|
|
71
|
+
|
|
72
|
+
Every call to a `write`- or `billing`-gated tool makes a **real, live network request** to `GET /v1/user-keys/self` on the OTPy API, presenting your configured `OTPY_USER_KEY` as a Bearer token. The API hashes it and looks up the *live* row in the `user_keys` table — the same credential's scopes can never be spoofed or bypassed locally. If the key has been revoked or its scopes downgraded on the dashboard, the very next tool call reflects that immediately; there is no local caching of scopes.
|
|
73
|
+
|
|
74
|
+
**There is no client-side override of any kind.** Earlier versions of this server had a local `OTPY_MCP_WRITE` / `--write` flag that only ever lived in this process's own config — it was never verified against the server, so anyone with shell/env access to their own MCP client could set it and bypass write-tool gating entirely. That flag has been removed outright (not deprecated, not silently downgraded to "restrict only" — deleted). If you still have `OTPY_MCP_WRITE`/`--write` set in an old config, it is now a complete no-op: `parseConfig` doesn't read it at all, and the only thing that can grant write/billing access is a real `user_key` with the matching scope, verified over the network on every call.
|
|
75
|
+
|
|
76
|
+
If no `OTPY_USER_KEY` is configured at all, every `write`/`billing`-gated tool is denied (fails closed) — only the unscoped read tools (`get_usage`, `get_integration_snippet`) keep working with just an API key.
|
|
77
|
+
|
|
78
|
+
### Project grants
|
|
79
|
+
|
|
80
|
+
A user key can optionally be restricted to specific projects (`user_project_grants`, set on the same Integrate tab). The rule:
|
|
81
|
+
|
|
82
|
+
- **Zero grant rows** → unrestricted: the key can act on any project its owner can reach.
|
|
83
|
+
- **One or more grant rows** → restricted to exactly those project ids.
|
|
84
|
+
|
|
85
|
+
Whenever a tool call includes a `project_id` argument, the server checks this alongside the write/billing scope check (same live network call) and denies the call if the presented user key isn't granted access to that project.
|
|
86
|
+
|
|
87
|
+
## Tools
|
|
88
|
+
|
|
89
|
+
| Tool | Required scope | Description |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `get_usage` | none | Daily quota and free/paid usage breakdown |
|
|
92
|
+
| `get_balance` | `billing` | Current wallet balance and pricing details |
|
|
93
|
+
| `list_api_keys` | `billing` | List project API keys and limits |
|
|
94
|
+
| `get_integration_snippet` | none | Generate copyable code snippets |
|
|
95
|
+
| `send_test_otp` | `write` | Send a test OTP code to a phone number |
|
|
96
|
+
| `verify_test_otp` | `write` | Verify a test OTP code |
|
|
97
|
+
| `create_api_key` | `write` | Create a new API key with custom limits |
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT © [OTPy.ir](https://otpy.ir)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export declare const SERVER_VERSION: string;
|
|
3
|
+
export interface McpServerConfig {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
userKey: string;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function parseConfig(args?: string[], env?: Record<string, string | undefined>): McpServerConfig;
|
|
9
|
+
export declare const TOOLS: ({
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
inputSchema: {
|
|
13
|
+
type: string;
|
|
14
|
+
properties: {
|
|
15
|
+
project_id?: undefined;
|
|
16
|
+
language?: undefined;
|
|
17
|
+
phone?: undefined;
|
|
18
|
+
code?: undefined;
|
|
19
|
+
name?: undefined;
|
|
20
|
+
limit_daily_otp?: undefined;
|
|
21
|
+
limit_weekly_otp?: undefined;
|
|
22
|
+
limit_monthly_otp?: undefined;
|
|
23
|
+
};
|
|
24
|
+
required: never[];
|
|
25
|
+
};
|
|
26
|
+
} | {
|
|
27
|
+
name: string;
|
|
28
|
+
description: string;
|
|
29
|
+
inputSchema: {
|
|
30
|
+
type: string;
|
|
31
|
+
properties: {
|
|
32
|
+
project_id: {
|
|
33
|
+
type: string;
|
|
34
|
+
description: string;
|
|
35
|
+
};
|
|
36
|
+
language?: undefined;
|
|
37
|
+
phone?: undefined;
|
|
38
|
+
code?: undefined;
|
|
39
|
+
name?: undefined;
|
|
40
|
+
limit_daily_otp?: undefined;
|
|
41
|
+
limit_weekly_otp?: undefined;
|
|
42
|
+
limit_monthly_otp?: undefined;
|
|
43
|
+
};
|
|
44
|
+
required: string[];
|
|
45
|
+
};
|
|
46
|
+
} | {
|
|
47
|
+
name: string;
|
|
48
|
+
description: string;
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: string;
|
|
51
|
+
properties: {
|
|
52
|
+
language: {
|
|
53
|
+
type: string;
|
|
54
|
+
enum: string[];
|
|
55
|
+
description: string;
|
|
56
|
+
};
|
|
57
|
+
project_id?: undefined;
|
|
58
|
+
phone?: undefined;
|
|
59
|
+
code?: undefined;
|
|
60
|
+
name?: undefined;
|
|
61
|
+
limit_daily_otp?: undefined;
|
|
62
|
+
limit_weekly_otp?: undefined;
|
|
63
|
+
limit_monthly_otp?: undefined;
|
|
64
|
+
};
|
|
65
|
+
required: string[];
|
|
66
|
+
};
|
|
67
|
+
} | {
|
|
68
|
+
name: string;
|
|
69
|
+
description: string;
|
|
70
|
+
inputSchema: {
|
|
71
|
+
type: string;
|
|
72
|
+
properties: {
|
|
73
|
+
phone: {
|
|
74
|
+
type: string;
|
|
75
|
+
description: string;
|
|
76
|
+
};
|
|
77
|
+
project_id?: undefined;
|
|
78
|
+
language?: undefined;
|
|
79
|
+
code?: undefined;
|
|
80
|
+
name?: undefined;
|
|
81
|
+
limit_daily_otp?: undefined;
|
|
82
|
+
limit_weekly_otp?: undefined;
|
|
83
|
+
limit_monthly_otp?: undefined;
|
|
84
|
+
};
|
|
85
|
+
required: string[];
|
|
86
|
+
};
|
|
87
|
+
} | {
|
|
88
|
+
name: string;
|
|
89
|
+
description: string;
|
|
90
|
+
inputSchema: {
|
|
91
|
+
type: string;
|
|
92
|
+
properties: {
|
|
93
|
+
phone: {
|
|
94
|
+
type: string;
|
|
95
|
+
description: string;
|
|
96
|
+
};
|
|
97
|
+
code: {
|
|
98
|
+
type: string;
|
|
99
|
+
description: string;
|
|
100
|
+
};
|
|
101
|
+
project_id?: undefined;
|
|
102
|
+
language?: undefined;
|
|
103
|
+
name?: undefined;
|
|
104
|
+
limit_daily_otp?: undefined;
|
|
105
|
+
limit_weekly_otp?: undefined;
|
|
106
|
+
limit_monthly_otp?: undefined;
|
|
107
|
+
};
|
|
108
|
+
required: string[];
|
|
109
|
+
};
|
|
110
|
+
} | {
|
|
111
|
+
name: string;
|
|
112
|
+
description: string;
|
|
113
|
+
inputSchema: {
|
|
114
|
+
type: string;
|
|
115
|
+
properties: {
|
|
116
|
+
project_id: {
|
|
117
|
+
type: string;
|
|
118
|
+
description: string;
|
|
119
|
+
};
|
|
120
|
+
name: {
|
|
121
|
+
type: string;
|
|
122
|
+
description: string;
|
|
123
|
+
};
|
|
124
|
+
limit_daily_otp: {
|
|
125
|
+
type: string;
|
|
126
|
+
description: string;
|
|
127
|
+
};
|
|
128
|
+
limit_weekly_otp: {
|
|
129
|
+
type: string;
|
|
130
|
+
description: string;
|
|
131
|
+
};
|
|
132
|
+
limit_monthly_otp: {
|
|
133
|
+
type: string;
|
|
134
|
+
description: string;
|
|
135
|
+
};
|
|
136
|
+
language?: undefined;
|
|
137
|
+
phone?: undefined;
|
|
138
|
+
code?: undefined;
|
|
139
|
+
};
|
|
140
|
+
required: string[];
|
|
141
|
+
};
|
|
142
|
+
})[];
|
|
143
|
+
export interface UserKeyScopes {
|
|
144
|
+
write: boolean;
|
|
145
|
+
billing: boolean;
|
|
146
|
+
root: boolean;
|
|
147
|
+
enabled: boolean;
|
|
148
|
+
}
|
|
149
|
+
export type ScopeVerification = {
|
|
150
|
+
ok: true;
|
|
151
|
+
scopes: UserKeyScopes;
|
|
152
|
+
projectAllowed: boolean | null;
|
|
153
|
+
} | {
|
|
154
|
+
ok: false;
|
|
155
|
+
reason: string;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Real, server-verified scope check -- a live network call to
|
|
159
|
+
* GET /v1/user-keys/self (packages/db/migrations/0018_user_key_authenticate.sql
|
|
160
|
+
* via apps/api/src/routes/v1/user-keys.ts), never a client-side-only flag.
|
|
161
|
+
*
|
|
162
|
+
* When no `userKey` is configured at all, this deliberately returns "ok" with
|
|
163
|
+
* every scope false rather than an error -- read-only tools (get_usage,
|
|
164
|
+
* get_integration_snippet) must keep working with only a project api_key
|
|
165
|
+
* configured, and write/billing tools must be denied (not crash) with a
|
|
166
|
+
* clear message telling the operator to configure OTPY_USER_KEY.
|
|
167
|
+
*/
|
|
168
|
+
export declare function verifyUserKeyScopes(config: McpServerConfig, fetchFn?: typeof fetch, projectId?: string): Promise<ScopeVerification>;
|
|
169
|
+
export declare function handleToolCall(name: string, args: Record<string, unknown>, config: McpServerConfig, fetchFn?: typeof fetch): Promise<{
|
|
170
|
+
content: {
|
|
171
|
+
type: "text";
|
|
172
|
+
text: string;
|
|
173
|
+
}[];
|
|
174
|
+
isError?: boolean;
|
|
175
|
+
}>;
|
|
176
|
+
export declare function startMcpServer(config?: McpServerConfig, input?: NodeJS.ReadableStream, output?: NodeJS.WritableStream): void;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
// Single source of truth for the server version: package.json. Read at runtime
|
|
5
|
+
// (rootDir is src/, so a static JSON import of ../package.json would break tsc).
|
|
6
|
+
export const SERVER_VERSION = createRequire(import.meta.url)("../package.json").version;
|
|
7
|
+
export function parseConfig(args = process.argv.slice(2), env = process.env) {
|
|
8
|
+
const apiKeyArgIdx = args.indexOf("--api-key");
|
|
9
|
+
const apiKey = (apiKeyArgIdx !== -1 && args[apiKeyArgIdx + 1]) ||
|
|
10
|
+
env.OTPY_API_KEY ||
|
|
11
|
+
"";
|
|
12
|
+
const userKeyArgIdx = args.indexOf("--user-key");
|
|
13
|
+
const userKey = (userKeyArgIdx !== -1 && args[userKeyArgIdx + 1]) ||
|
|
14
|
+
env.OTPY_USER_KEY ||
|
|
15
|
+
"";
|
|
16
|
+
const baseUrlArgIdx = args.indexOf("--base-url");
|
|
17
|
+
const baseUrl = (baseUrlArgIdx !== -1 && args[baseUrlArgIdx + 1]) ||
|
|
18
|
+
env.OTPY_BASE_URL ||
|
|
19
|
+
"https://api.otpy.ir";
|
|
20
|
+
return { apiKey, userKey, baseUrl };
|
|
21
|
+
}
|
|
22
|
+
export const TOOLS = [
|
|
23
|
+
{
|
|
24
|
+
name: "get_usage",
|
|
25
|
+
description: "Get today's OTP usage statistics (free used, free quota, paid count, daily limit).",
|
|
26
|
+
inputSchema: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {},
|
|
29
|
+
required: [],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "get_balance",
|
|
34
|
+
description: "Get the current wallet balance for a project. Requires a user_key with the 'billing' scope (see README).",
|
|
35
|
+
inputSchema: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
project_id: { type: "string", description: "Project ID." },
|
|
39
|
+
},
|
|
40
|
+
required: ["project_id"],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "list_api_keys",
|
|
45
|
+
description: "List active API keys and their configured quota limits for the project. Requires a user_key with the 'billing' scope (see README).",
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
project_id: { type: "string", description: "Project ID." },
|
|
50
|
+
},
|
|
51
|
+
required: ["project_id"],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "get_integration_snippet",
|
|
56
|
+
description: "Get ready-to-use code integration snippet for a specific language (nodejs, python, go, php, curl, csharp).",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
language: {
|
|
61
|
+
type: "string",
|
|
62
|
+
enum: ["nodejs", "python", "go", "php", "curl", "csharp"],
|
|
63
|
+
description: "Target programming language.",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
required: ["language"],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "send_test_otp",
|
|
71
|
+
description: "Send a test login OTP to a phone number. Requires a user_key with the 'write' scope, verified live against the OTPy API (see README).",
|
|
72
|
+
inputSchema: {
|
|
73
|
+
type: "object",
|
|
74
|
+
properties: {
|
|
75
|
+
phone: { type: "string", description: "Iranian phone number in format 09xxxxxxxxx." },
|
|
76
|
+
},
|
|
77
|
+
required: ["phone"],
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "verify_test_otp",
|
|
82
|
+
description: "Verify a test OTP code for a phone number. Requires a user_key with the 'write' scope, verified live against the OTPy API (see README).",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
phone: { type: "string", description: "Iranian phone number in format 09xxxxxxxxx." },
|
|
87
|
+
code: { type: "string", description: "6-digit OTP code." },
|
|
88
|
+
},
|
|
89
|
+
required: ["phone", "code"],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "create_api_key",
|
|
94
|
+
description: "Create a new API key with optional daily/weekly/monthly limits. Requires a user_key with the 'write' scope, verified live against the OTPy API (see README).",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
type: "object",
|
|
97
|
+
properties: {
|
|
98
|
+
project_id: { type: "string", description: "Project ID." },
|
|
99
|
+
name: { type: "string", description: "Key name." },
|
|
100
|
+
limit_daily_otp: { type: "number", description: "Optional daily OTP limit." },
|
|
101
|
+
limit_weekly_otp: { type: "number", description: "Optional weekly OTP limit." },
|
|
102
|
+
limit_monthly_otp: { type: "number", description: "Optional monthly OTP limit." },
|
|
103
|
+
},
|
|
104
|
+
required: ["project_id", "name"],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
// Tools requiring the `write` scope on the presented user_key.
|
|
109
|
+
const WRITE_TOOLS = ["send_test_otp", "verify_test_otp", "create_api_key"];
|
|
110
|
+
// Tools requiring the `billing` scope on the presented user_key.
|
|
111
|
+
// Mapping per the plan: billing -> get_balance/list_api_keys/topup endpoints.
|
|
112
|
+
// `root` is never a separate gate -- it is just "has both write AND billing".
|
|
113
|
+
const BILLING_TOOLS = ["get_balance", "list_api_keys"];
|
|
114
|
+
/**
|
|
115
|
+
* Real, server-verified scope check -- a live network call to
|
|
116
|
+
* GET /v1/user-keys/self (packages/db/migrations/0018_user_key_authenticate.sql
|
|
117
|
+
* via apps/api/src/routes/v1/user-keys.ts), never a client-side-only flag.
|
|
118
|
+
*
|
|
119
|
+
* When no `userKey` is configured at all, this deliberately returns "ok" with
|
|
120
|
+
* every scope false rather than an error -- read-only tools (get_usage,
|
|
121
|
+
* get_integration_snippet) must keep working with only a project api_key
|
|
122
|
+
* configured, and write/billing tools must be denied (not crash) with a
|
|
123
|
+
* clear message telling the operator to configure OTPY_USER_KEY.
|
|
124
|
+
*/
|
|
125
|
+
export async function verifyUserKeyScopes(config, fetchFn = globalThis.fetch, projectId) {
|
|
126
|
+
if (!config.userKey) {
|
|
127
|
+
return {
|
|
128
|
+
ok: true,
|
|
129
|
+
scopes: { write: false, billing: false, root: false, enabled: false },
|
|
130
|
+
projectAllowed: null,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const url = new URL(`${config.baseUrl}/v1/user-keys/self`);
|
|
135
|
+
if (projectId)
|
|
136
|
+
url.searchParams.set("project_id", projectId);
|
|
137
|
+
const res = await fetchFn(url.toString(), {
|
|
138
|
+
headers: { authorization: `Bearer ${config.userKey}` },
|
|
139
|
+
});
|
|
140
|
+
if (res.status === 401) {
|
|
141
|
+
return { ok: false, reason: "The configured user_key was rejected (invalid, unknown, or revoked)." };
|
|
142
|
+
}
|
|
143
|
+
if (!res.ok) {
|
|
144
|
+
return { ok: false, reason: `Scope verification request failed with status ${res.status}.` };
|
|
145
|
+
}
|
|
146
|
+
const data = (await res.json());
|
|
147
|
+
if (typeof data.write !== "boolean" || typeof data.billing !== "boolean") {
|
|
148
|
+
return { ok: false, reason: "Scope verification response was malformed." };
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
ok: true,
|
|
152
|
+
scopes: {
|
|
153
|
+
write: data.write,
|
|
154
|
+
billing: data.billing,
|
|
155
|
+
root: Boolean(data.root),
|
|
156
|
+
enabled: Boolean(data.enabled),
|
|
157
|
+
},
|
|
158
|
+
projectAllowed: typeof data.project_allowed === "boolean" ? data.project_allowed : null,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
return { ok: false, reason: `Network error while verifying user_key scopes: ${String(err)}` };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function scopeDeniedResult(text) {
|
|
166
|
+
return { isError: true, content: [{ type: "text", text }] };
|
|
167
|
+
}
|
|
168
|
+
export async function handleToolCall(name, args, config, fetchFn = globalThis.fetch) {
|
|
169
|
+
const needsWrite = WRITE_TOOLS.includes(name);
|
|
170
|
+
const needsBilling = BILLING_TOOLS.includes(name);
|
|
171
|
+
if (needsWrite || needsBilling) {
|
|
172
|
+
const projectId = typeof args.project_id === "string" ? args.project_id : undefined;
|
|
173
|
+
const verification = await verifyUserKeyScopes(config, fetchFn, projectId);
|
|
174
|
+
if (!verification.ok) {
|
|
175
|
+
return scopeDeniedResult(`❌ Could not verify this MCP connection's user_key scopes: ${verification.reason}\nConfigure a valid user_key (OTPY_USER_KEY / --user-key), obtained from the "Integrate" tab on https://dash.otpy.ir.`);
|
|
176
|
+
}
|
|
177
|
+
if (!verification.scopes.enabled) {
|
|
178
|
+
return scopeDeniedResult(`❌ No valid user_key is configured for this MCP connection.\nThis tool requires a user_key with the required scope. Create one on the "Integrate" tab at https://dash.otpy.ir and set OTPY_USER_KEY (or --user-key).`);
|
|
179
|
+
}
|
|
180
|
+
if (needsWrite && !verification.scopes.write) {
|
|
181
|
+
return scopeDeniedResult(`❌ This MCP connection's user_key does not have the 'write' scope.\nWrite actions (sending test OTPs, creating/modifying keys) require a user_key with write enabled. Configure this on the "Integrate" tab at https://dash.otpy.ir.`);
|
|
182
|
+
}
|
|
183
|
+
if (needsBilling && !verification.scopes.billing) {
|
|
184
|
+
return scopeDeniedResult(`❌ This MCP connection's user_key does not have the 'billing' scope.\nBilling-related reads (balance, API key listing) require a user_key with billing enabled. Configure this on the "Integrate" tab at https://dash.otpy.ir.`);
|
|
185
|
+
}
|
|
186
|
+
if (projectId && verification.projectAllowed === false) {
|
|
187
|
+
return scopeDeniedResult(`❌ This MCP connection's user_key is not granted access to project ${projectId}.\nEither omit project_id, or grant this user_key access to that project on the "Integrate" tab at https://dash.otpy.ir.`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (name === "get_usage") {
|
|
191
|
+
if (!config.apiKey) {
|
|
192
|
+
return { isError: true, content: [{ type: "text", text: "Error: OTPY_API_KEY is not configured." }] };
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const res = await fetchFn(`${config.baseUrl}/v1/usage`, {
|
|
196
|
+
headers: { authorization: `Bearer ${config.apiKey}` },
|
|
197
|
+
});
|
|
198
|
+
const data = await res.json();
|
|
199
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
return { isError: true, content: [{ type: "text", text: `Network error: ${String(err)}` }] };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (name === "get_balance") {
|
|
206
|
+
const projectId = typeof args.project_id === "string" && args.project_id ? args.project_id : null;
|
|
207
|
+
if (!projectId) {
|
|
208
|
+
return { isError: true, content: [{ type: "text", text: "Error: project_id is required." }] };
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
const url = new URL(`${config.baseUrl}/v1/mcp-scope/balance`);
|
|
212
|
+
url.searchParams.set("project_id", projectId);
|
|
213
|
+
const res = await fetchFn(url.toString(), {
|
|
214
|
+
headers: { authorization: `Bearer ${config.userKey}` },
|
|
215
|
+
});
|
|
216
|
+
const data = await res.json();
|
|
217
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
return { isError: true, content: [{ type: "text", text: `Network error: ${String(err)}` }] };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (name === "get_integration_snippet") {
|
|
224
|
+
const lang = String(args.language || "nodejs");
|
|
225
|
+
const key = config.apiKey || "otpy_your_api_key";
|
|
226
|
+
let snippet = "";
|
|
227
|
+
if (lang === "python") {
|
|
228
|
+
snippet = `import requests\nres = requests.post("https://api.otpy.ir/v1/otp/send", json={"phone": "09123456789"}, headers={"Authorization": "Bearer ${key}"})\nprint(res.json())`;
|
|
229
|
+
}
|
|
230
|
+
else if (lang === "curl") {
|
|
231
|
+
snippet = `curl -X POST https://api.otpy.ir/v1/otp/send -H "Authorization: Bearer ${key}" -H "Content-Type: application/json" -d '{"phone": "09123456789"}'`;
|
|
232
|
+
}
|
|
233
|
+
else if (lang === "go") {
|
|
234
|
+
snippet = `package main\n\nimport (\n\t"bytes"\n\t"encoding/json"\n\t"fmt"\n\t"net/http"\n)\n\nfunc main() {\n\tpayload, _ := json.Marshal(map[string]string{"phone": "09123456789"})\n\treq, _ := http.NewRequest("POST", "https://api.otpy.ir/v1/otp/send", bytes.NewBuffer(payload))\n\treq.Header.Set("Authorization", "Bearer ${key}")\n\treq.Header.Set("Content-Type", "application/json")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n\tvar result map[string]any\n\tjson.NewDecoder(resp.Body).Decode(&result)\n\tfmt.Println(result)\n}`;
|
|
235
|
+
}
|
|
236
|
+
else if (lang === "php") {
|
|
237
|
+
snippet = `<?php\nuse Illuminate\\Support\\Facades\\Http;\n\n$response = Http::withToken('${key}')\n ->acceptJson()\n ->post('https://api.otpy.ir/v1/otp/send', [\n 'phone' => '09123456789',\n ]);\n\nreturn $response->json();`;
|
|
238
|
+
}
|
|
239
|
+
else if (lang === "csharp") {
|
|
240
|
+
snippet = `using System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Text;\n\nusing var client = new HttpClient();\nclient.DefaultRequestHeaders.Authorization =\n new AuthenticationHeaderValue("Bearer", "${key}");\n\nvar content = new StringContent(\n "{\\"phone\\":\\"09123456789\\"}",\n Encoding.UTF8,\n "application/json");\n\nvar response = await client.PostAsync("https://api.otpy.ir/v1/otp/send", content);\nvar body = await response.Content.ReadAsStringAsync();\nConsole.WriteLine(body);`;
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
snippet = `import { OtpyClient } from "@o-t-p-y/sdk";\nconst otpy = new OtpyClient({ apiKey: "${key}" });\nawait otpy.sendOtp("09123456789");`;
|
|
244
|
+
}
|
|
245
|
+
return { content: [{ type: "text", text: snippet }] };
|
|
246
|
+
}
|
|
247
|
+
if (name === "send_test_otp") {
|
|
248
|
+
const phone = String(args.phone || "");
|
|
249
|
+
if (!/^09\d{9}$/.test(phone)) {
|
|
250
|
+
return { isError: true, content: [{ type: "text", text: "Invalid phone format. Expected 09xxxxxxxxx." }] };
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
253
|
+
const res = await fetchFn(`${config.baseUrl}/v1/otp/send`, {
|
|
254
|
+
method: "POST",
|
|
255
|
+
headers: {
|
|
256
|
+
authorization: `Bearer ${config.apiKey}`,
|
|
257
|
+
"content-type": "application/json",
|
|
258
|
+
},
|
|
259
|
+
body: JSON.stringify({ phone }),
|
|
260
|
+
});
|
|
261
|
+
const data = await res.json();
|
|
262
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
return { isError: true, content: [{ type: "text", text: `Network error: ${String(err)}` }] };
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (name === "verify_test_otp") {
|
|
269
|
+
const phone = String(args.phone || "");
|
|
270
|
+
const code = String(args.code || "");
|
|
271
|
+
try {
|
|
272
|
+
const res = await fetchFn(`${config.baseUrl}/v1/otp/verify`, {
|
|
273
|
+
method: "POST",
|
|
274
|
+
headers: {
|
|
275
|
+
authorization: `Bearer ${config.apiKey}`,
|
|
276
|
+
"content-type": "application/json",
|
|
277
|
+
},
|
|
278
|
+
body: JSON.stringify({ phone, code }),
|
|
279
|
+
});
|
|
280
|
+
const data = await res.json();
|
|
281
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
return { isError: true, content: [{ type: "text", text: `Network error: ${String(err)}` }] };
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (name === "list_api_keys") {
|
|
288
|
+
const projectId = typeof args.project_id === "string" && args.project_id ? args.project_id : null;
|
|
289
|
+
if (!projectId) {
|
|
290
|
+
return { isError: true, content: [{ type: "text", text: "Error: project_id is required." }] };
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
const res = await fetchFn(`${config.baseUrl}/v1/mcp-scope/projects/${projectId}/api-keys`, {
|
|
294
|
+
headers: { authorization: `Bearer ${config.userKey}` },
|
|
295
|
+
});
|
|
296
|
+
const data = await res.json();
|
|
297
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
return { isError: true, content: [{ type: "text", text: `Network error: ${String(err)}` }] };
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (name === "create_api_key") {
|
|
304
|
+
const projectId = typeof args.project_id === "string" && args.project_id ? args.project_id : null;
|
|
305
|
+
if (!projectId) {
|
|
306
|
+
return { isError: true, content: [{ type: "text", text: "Error: project_id is required." }] };
|
|
307
|
+
}
|
|
308
|
+
const body = { name: String(args.name ?? "") };
|
|
309
|
+
for (const key of ["limit_daily_otp", "limit_weekly_otp", "limit_monthly_otp"]) {
|
|
310
|
+
if (typeof args[key] === "number")
|
|
311
|
+
body[key] = args[key];
|
|
312
|
+
}
|
|
313
|
+
try {
|
|
314
|
+
const res = await fetchFn(`${config.baseUrl}/v1/mcp-scope/projects/${projectId}/api-keys`, {
|
|
315
|
+
method: "POST",
|
|
316
|
+
headers: {
|
|
317
|
+
authorization: `Bearer ${config.userKey}`,
|
|
318
|
+
"content-type": "application/json",
|
|
319
|
+
},
|
|
320
|
+
body: JSON.stringify(body),
|
|
321
|
+
});
|
|
322
|
+
const data = await res.json();
|
|
323
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
324
|
+
}
|
|
325
|
+
catch (err) {
|
|
326
|
+
return { isError: true, content: [{ type: "text", text: `Network error: ${String(err)}` }] };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return { isError: true, content: [{ type: "text", text: `Unknown tool: ${name}` }] };
|
|
330
|
+
}
|
|
331
|
+
export function startMcpServer(config = parseConfig(), input = process.stdin, output = process.stdout) {
|
|
332
|
+
const rl = createInterface({ input, terminal: false });
|
|
333
|
+
rl.on("line", async (line) => {
|
|
334
|
+
const trimmed = line.trim();
|
|
335
|
+
if (!trimmed)
|
|
336
|
+
return;
|
|
337
|
+
let request;
|
|
338
|
+
try {
|
|
339
|
+
request = JSON.parse(trimmed);
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
output.write(JSON.stringify({
|
|
343
|
+
jsonrpc: "2.0",
|
|
344
|
+
id: null,
|
|
345
|
+
error: { code: -32700, message: "Parse error" },
|
|
346
|
+
}) + "\n");
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (!request.method)
|
|
350
|
+
return;
|
|
351
|
+
if (request.method === "initialize") {
|
|
352
|
+
output.write(JSON.stringify({
|
|
353
|
+
jsonrpc: "2.0",
|
|
354
|
+
id: request.id,
|
|
355
|
+
result: {
|
|
356
|
+
protocolVersion: "2024-11-05",
|
|
357
|
+
capabilities: { tools: {} },
|
|
358
|
+
serverInfo: {
|
|
359
|
+
name: "otpy-mcp",
|
|
360
|
+
version: SERVER_VERSION,
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
}) + "\n");
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (request.method === "notifications/initialized") {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
if (request.method === "ping") {
|
|
370
|
+
output.write(JSON.stringify({ jsonrpc: "2.0", id: request.id, result: {} }) + "\n");
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (request.method === "tools/list") {
|
|
374
|
+
output.write(JSON.stringify({
|
|
375
|
+
jsonrpc: "2.0",
|
|
376
|
+
id: request.id,
|
|
377
|
+
result: { tools: TOOLS },
|
|
378
|
+
}) + "\n");
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (request.method === "tools/call") {
|
|
382
|
+
const toolName = String(request.params?.name || "");
|
|
383
|
+
const toolArgs = (request.params?.arguments ||
|
|
384
|
+
{});
|
|
385
|
+
const res = await handleToolCall(toolName, toolArgs, config);
|
|
386
|
+
output.write(JSON.stringify({
|
|
387
|
+
jsonrpc: "2.0",
|
|
388
|
+
id: request.id,
|
|
389
|
+
result: res,
|
|
390
|
+
}) + "\n");
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
output.write(JSON.stringify({
|
|
394
|
+
jsonrpc: "2.0",
|
|
395
|
+
id: request.id,
|
|
396
|
+
error: { code: -32601, message: `Method not found: ${request.method}` },
|
|
397
|
+
}) + "\n");
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
// Auto-start when executed directly
|
|
401
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
402
|
+
startMcpServer();
|
|
403
|
+
}
|
|
404
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@o-t-p-y/mcp",
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "OTPy MCP server — agent-driven integration path. Implemented in P5.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/o-t-p-y/mcp.git"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"otpy-mcp": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -p tsconfig.json",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"test": "vitest run --passWithNoTests"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^22.10.2",
|
|
29
|
+
"typescript": "^5.7.2",
|
|
30
|
+
"vitest": "^3.2.4"
|
|
31
|
+
}
|
|
32
|
+
}
|