@pyai/mcp 0.5.0 → 0.5.1
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/AGENT_GUIDE.md +14 -0
- package/README.md +14 -0
- package/dist/extra-tools.js +4 -4
- package/dist/generated-tools.js +26 -4
- package/dist/hosted-policy.js +33 -0
- package/dist/server.js +11 -9
- package/dist/tools.js +28 -9
- package/dist/workflows.js +19 -0
- package/package.json +1 -1
package/AGENT_GUIDE.md
CHANGED
|
@@ -84,3 +84,17 @@ limits. Authorized organization, project and key IDs remain in structured
|
|
|
84
84
|
output; `whoami({"verbose":true})` also includes them in text. This reduces
|
|
85
85
|
prompt clutter, not host access to identity metadata. Credential-shaped fields
|
|
86
86
|
are omitted in both modes. Never paste keys or full identity dumps into reports.
|
|
87
|
+
|
|
88
|
+
## Hosted connection boundaries
|
|
89
|
+
|
|
90
|
+
The hosted OAuth MCP connection uses existing PyAI projects and owned phone numbers.
|
|
91
|
+
Number purchasing is not exposed through hosted MCP. The REST API and local stdio
|
|
92
|
+
integration retain their separate contracts. Hosted agent tool bindings accept
|
|
93
|
+
saved tool IDs and enabled flags, not credentials or arbitrary connection settings.
|
|
94
|
+
Configure those settings privately in the PyAI console. Retained bindings preserve
|
|
95
|
+
their saved settings, and hosted agent responses omit connection configuration.
|
|
96
|
+
|
|
97
|
+
Supply only audio and text you are authorized to process. Do not submit payment-card
|
|
98
|
+
data, protected health information, government identifiers, passwords, or API keys.
|
|
99
|
+
If an operation exceeds the project's entitlement, report the limitation without
|
|
100
|
+
initiating a purchase or repeatedly resubmitting the request.
|
package/README.md
CHANGED
|
@@ -138,3 +138,17 @@ limits. Authorized organization, project and key IDs remain in structured
|
|
|
138
138
|
output; `whoami({"verbose":true})` also includes them in text. This reduces
|
|
139
139
|
prompt clutter, not host access to identity metadata. Credential-shaped fields
|
|
140
140
|
are omitted in both modes. Never paste keys or full identity dumps into reports.
|
|
141
|
+
|
|
142
|
+
## Hosted connection boundaries
|
|
143
|
+
|
|
144
|
+
The hosted OAuth MCP connection uses existing PyAI projects and owned phone numbers.
|
|
145
|
+
Number purchasing is not exposed through hosted MCP. The REST API and local stdio
|
|
146
|
+
integration retain their separate contracts. Hosted agent tool bindings accept
|
|
147
|
+
saved tool IDs and enabled flags, not credentials or arbitrary connection settings.
|
|
148
|
+
Configure those settings privately in the PyAI console. Retained bindings preserve
|
|
149
|
+
their saved settings, and hosted agent responses omit connection configuration.
|
|
150
|
+
|
|
151
|
+
Supply only audio and text you are authorized to process. Do not submit payment-card
|
|
152
|
+
data, protected health information, government identifiers, passwords, or API keys.
|
|
153
|
+
If an operation exceeds the project's entitlement, report the limitation without
|
|
154
|
+
initiating a purchase or repeatedly resubmitting the request.
|
package/dist/extra-tools.js
CHANGED
|
@@ -28,7 +28,7 @@ export const EXTRA_TOOLS = [
|
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
name: "create_dub",
|
|
31
|
-
description: "
|
|
31
|
+
description: "Fetch audio from the user-authorized HTTPS source URL and start a translation and dubbing job. Accesses an external source and consumes usage. Keep job_id and poll get_dub_job; do not submit again after a timeout.",
|
|
32
32
|
inputSchema: obj({
|
|
33
33
|
source_url: { type: "string", format: "uri", pattern: "^https://" },
|
|
34
34
|
source_lang: string("Source language from get_dub_capabilities."),
|
|
@@ -37,8 +37,8 @@ export const EXTRA_TOOLS = [
|
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
name: "get_dub_job",
|
|
40
|
-
title: "
|
|
41
|
-
description: "
|
|
40
|
+
title: "Get dubbing job status",
|
|
41
|
+
description: "Retrieve the status and available results of an existing dubbing job by job_id. This read does not start or repeat a job. Poll pending/processing states without resubmitting.",
|
|
42
42
|
inputSchema: obj(id, ["job_id"]),
|
|
43
43
|
},
|
|
44
44
|
{
|
|
@@ -88,7 +88,7 @@ export const EXTRA_TOOLS = [
|
|
|
88
88
|
},
|
|
89
89
|
language: {
|
|
90
90
|
type: "string",
|
|
91
|
-
enum: ["en", "es", "fr", "de", "hi", "it", "pt", "nl"],
|
|
91
|
+
enum: ["en", "es", "fr", "de", "hi", "it", "pt", "nl", "zh", "yue", "ar", "id", "ko", "th", "vi", "ja", "tr", "ms", "sv", "da", "fi", "pl", "cs", "fil", "fa", "el", "hu", "mk", "ro"],
|
|
92
92
|
},
|
|
93
93
|
}, ["audio_base64", "filename"]),
|
|
94
94
|
},
|
package/dist/generated-tools.js
CHANGED
|
@@ -609,7 +609,7 @@ export const API_TOOLS = [
|
|
|
609
609
|
"null"
|
|
610
610
|
],
|
|
611
611
|
"maxLength": 200,
|
|
612
|
-
"description": "
|
|
612
|
+
"description": "Stored delivery direction for instruct-capable voice tiers. Current Omni routes support neutral delivery only: omit or set null for neutral speech. A saved custom value is rejected when configuring Omni; an inline empty `configure.voice_instruct` resets it to neutral for that session."
|
|
613
613
|
},
|
|
614
614
|
"brain_model": {
|
|
615
615
|
"type": [
|
|
@@ -686,9 +686,20 @@ export const API_TOOLS = [
|
|
|
686
686
|
"es",
|
|
687
687
|
"de",
|
|
688
688
|
"hi",
|
|
689
|
+
"zh",
|
|
690
|
+
"it",
|
|
691
|
+
"pt",
|
|
692
|
+
"ja",
|
|
693
|
+
"ko",
|
|
689
694
|
null
|
|
690
695
|
],
|
|
691
|
-
"
|
|
696
|
+
"x-staged-language-ids": [
|
|
697
|
+
"ht",
|
|
698
|
+
"zh-CN",
|
|
699
|
+
"ar-MSA",
|
|
700
|
+
"ar-Gulf"
|
|
701
|
+
],
|
|
702
|
+
"description": "Requested language for this Agent's Omni sessions. `null` or absent means `en`. Availability is staged: public serving includes `en`, `fr`, `es`, `hi`, `it`, `pt`, `ja`, and `ko`; `de` and the legacy `zh` alias fall back to English unless explicitly enabled with qualified endpoints. Canonical staged route identifiers are exposed in `x-staged-language-ids` for internal integration only and are rejected by the public control plane until qualified. Inspect the session's `configured.language_active` and `language_fallback` fields before assuming the requested language is active. See the Language support reference."
|
|
692
703
|
},
|
|
693
704
|
"metadata": {
|
|
694
705
|
"type": [
|
|
@@ -936,7 +947,7 @@ export const API_TOOLS = [
|
|
|
936
947
|
"null"
|
|
937
948
|
],
|
|
938
949
|
"maxLength": 200,
|
|
939
|
-
"description": "
|
|
950
|
+
"description": "Stored delivery direction for instruct-capable voice tiers. Current Omni routes support neutral delivery only: omit or set null for neutral speech. A saved custom value is rejected when configuring Omni; an inline empty `configure.voice_instruct` resets it to neutral for that session."
|
|
940
951
|
},
|
|
941
952
|
"brain_model": {
|
|
942
953
|
"type": [
|
|
@@ -1013,9 +1024,20 @@ export const API_TOOLS = [
|
|
|
1013
1024
|
"es",
|
|
1014
1025
|
"de",
|
|
1015
1026
|
"hi",
|
|
1027
|
+
"zh",
|
|
1028
|
+
"it",
|
|
1029
|
+
"pt",
|
|
1030
|
+
"ja",
|
|
1031
|
+
"ko",
|
|
1016
1032
|
null
|
|
1017
1033
|
],
|
|
1018
|
-
"
|
|
1034
|
+
"x-staged-language-ids": [
|
|
1035
|
+
"ht",
|
|
1036
|
+
"zh-CN",
|
|
1037
|
+
"ar-MSA",
|
|
1038
|
+
"ar-Gulf"
|
|
1039
|
+
],
|
|
1040
|
+
"description": "Requested language for this Agent's Omni sessions. `null` or absent means `en`. Availability is staged: public serving includes `en`, `fr`, `es`, `hi`, `it`, `pt`, `ja`, and `ko`; `de` and the legacy `zh` alias fall back to English unless explicitly enabled with qualified endpoints. Canonical staged route identifiers are exposed in `x-staged-language-ids` for internal integration only and are rejected by the public control plane until qualified. Inspect the session's `configured.language_active` and `language_fallback` fields before assuming the requested language is active. See the Language support reference."
|
|
1019
1041
|
},
|
|
1020
1042
|
"metadata": {
|
|
1021
1043
|
"type": [
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Remote conversational clients use saved connections, never credential inputs
|
|
2
|
+
// or digital-service checkout. The REST API and local stdio retain their contract.
|
|
3
|
+
export const HOSTED_EXCLUDED_TOOLS = new Set(["create_sandbox_key", "telephony_buy_number"]);
|
|
4
|
+
export const AGENT_WRITE_TOOLS = new Set(["create_agent", "update_agent", "set_agent_tools"]);
|
|
5
|
+
export function hostedTools(tools) {
|
|
6
|
+
return tools.filter(t => !HOSTED_EXCLUDED_TOOLS.has(t.name)).map(t => {
|
|
7
|
+
if (!AGENT_WRITE_TOOLS.has(t.name))
|
|
8
|
+
return t;
|
|
9
|
+
const schema = structuredClone(t.inputSchema);
|
|
10
|
+
const body = schema.properties.body;
|
|
11
|
+
body.additionalProperties = false;
|
|
12
|
+
const bindings = t.name === "set_agent_tools" ? body : body.properties.tools;
|
|
13
|
+
if (bindings?.items) {
|
|
14
|
+
bindings.items = {
|
|
15
|
+
type: "object", required: ["tool_id"], additionalProperties: false,
|
|
16
|
+
properties: {
|
|
17
|
+
tool_id: { type: "string", description: "ID of an existing tool. Configure its connection privately in the PyAI console." },
|
|
18
|
+
enabled: { type: "boolean", default: true },
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
bindings.description = "Replace bindings using saved tool IDs. Existing settings are preserved for retained bindings. Credentials and connection settings are not accepted through MCP.";
|
|
22
|
+
}
|
|
23
|
+
return { ...t, inputSchema: schema, description: t.description + " Use saved tool IDs; configure connection settings privately in the PyAI console. Never supply credentials." };
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
export function withoutBindingConfig(value) {
|
|
27
|
+
if (Array.isArray(value))
|
|
28
|
+
return value.map(withoutBindingConfig);
|
|
29
|
+
if (!value || typeof value !== "object")
|
|
30
|
+
return value;
|
|
31
|
+
return Object.fromEntries(Object.entries(value).filter(([key]) => key !== "config")
|
|
32
|
+
.map(([key, entry]) => [key, withoutBindingConfig(entry)]));
|
|
33
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
2
|
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, McpError, ErrorCode, } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
-
import { TOOLS, TOOL_SCOPES, callTool, localContext, } from "./tools.js";
|
|
4
|
-
import {
|
|
5
|
-
export const MCP_VERSION = "0.5.
|
|
3
|
+
import { TOOLS, HOSTED_TOOLS, TOOL_SCOPES, callTool, localContext, } from "./tools.js";
|
|
4
|
+
import { RESOURCES, workflowsForMode, guideForMode, instructionsForMode, } from "./workflows.js";
|
|
5
|
+
export const MCP_VERSION = "0.5.1";
|
|
6
6
|
export function createMcpServer(client, context = localContext) {
|
|
7
|
+
const tools = context.mode === "http" ? HOSTED_TOOLS : TOOLS;
|
|
8
|
+
const workflows = workflowsForMode(context.mode);
|
|
7
9
|
const server = new Server({
|
|
8
10
|
name: "pyai",
|
|
9
11
|
version: MCP_VERSION,
|
|
@@ -11,10 +13,10 @@ export function createMcpServer(client, context = localContext) {
|
|
|
11
13
|
websiteUrl: "https://pyai.com/mcp",
|
|
12
14
|
}, {
|
|
13
15
|
capabilities: { tools: {}, resources: {}, prompts: {} },
|
|
14
|
-
instructions:
|
|
16
|
+
instructions: instructionsForMode(context.mode),
|
|
15
17
|
});
|
|
16
18
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
17
|
-
tools:
|
|
19
|
+
tools: tools.map((t) => context.mode === "stdio"
|
|
18
20
|
? t
|
|
19
21
|
: {
|
|
20
22
|
...t,
|
|
@@ -36,7 +38,7 @@ export function createMcpServer(client, context = localContext) {
|
|
|
36
38
|
}),
|
|
37
39
|
}));
|
|
38
40
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
39
|
-
if (!
|
|
41
|
+
if (!tools.some((t) => t.name === request.params.name) ||
|
|
40
42
|
(context.mode === "http" && request.params.name === "create_sandbox_key"))
|
|
41
43
|
throw new McpError(ErrorCode.InvalidParams, "Unknown tool.");
|
|
42
44
|
return (await callTool(request.params.name, request.params.arguments ?? {}, client, context));
|
|
@@ -53,13 +55,13 @@ export function createMcpServer(client, context = localContext) {
|
|
|
53
55
|
{
|
|
54
56
|
uri: resource.uri,
|
|
55
57
|
mimeType: resource.mimeType,
|
|
56
|
-
text: resource.uri === "pyai://guide" ?
|
|
58
|
+
text: resource.uri === "pyai://guide" ? guideForMode(context.mode) : JSON.stringify(workflows),
|
|
57
59
|
},
|
|
58
60
|
],
|
|
59
61
|
};
|
|
60
62
|
});
|
|
61
63
|
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
62
|
-
prompts: Object.entries(
|
|
64
|
+
prompts: Object.entries(workflows).map(([name, w]) => ({
|
|
63
65
|
name,
|
|
64
66
|
title: w.title,
|
|
65
67
|
description: w.example,
|
|
@@ -73,7 +75,7 @@ export function createMcpServer(client, context = localContext) {
|
|
|
73
75
|
})),
|
|
74
76
|
}));
|
|
75
77
|
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
76
|
-
const workflow =
|
|
78
|
+
const workflow = workflows[request.params.name];
|
|
77
79
|
if (!workflow || !request.params.arguments?.task)
|
|
78
80
|
throw new McpError(ErrorCode.InvalidParams, "Choose a workflow and provide task.");
|
|
79
81
|
return {
|
package/dist/tools.js
CHANGED
|
@@ -14,8 +14,10 @@ import { resolve, relative, isAbsolute, dirname, basename } from "node:path";
|
|
|
14
14
|
import { Ajv } from "ajv";
|
|
15
15
|
import { API_TOOLS } from "./generated-tools.js";
|
|
16
16
|
import { EXTRA_TOOLS, EXTRA_SCOPES, extraTool } from "./extra-tools.js";
|
|
17
|
-
import {
|
|
17
|
+
import { SEARCH_TERMS } from "./workflows.js";
|
|
18
18
|
import { PyAIError } from "./client.js";
|
|
19
|
+
import { hostedTools, AGENT_WRITE_TOOLS, withoutBindingConfig } from "./hosted-policy.js";
|
|
20
|
+
import { workflowsForMode, guideForMode } from "./workflows.js";
|
|
19
21
|
import { openapiGet } from "./contract.js";
|
|
20
22
|
const SPEECH_CALLING_GUIDE = "https://pyai.com/agents/speech-calling.md";
|
|
21
23
|
export const localContext = {
|
|
@@ -437,7 +439,7 @@ export const TOOLS = [
|
|
|
437
439
|
destructiveHint: ["configure_amd", "enable_recap"].includes(t.name),
|
|
438
440
|
idempotentHint: readOnly.has(t.name),
|
|
439
441
|
openWorldHint: !readOnly.has(t.name) &&
|
|
440
|
-
!["synthesize_speech", "
|
|
442
|
+
!["synthesize_speech", "preview_cast_line", "transcribe_audio"].includes(t.name),
|
|
441
443
|
},
|
|
442
444
|
_meta: {
|
|
443
445
|
"pyai/docs_url": SPEECH_CALLING_GUIDE,
|
|
@@ -446,8 +448,10 @@ export const TOOLS = [
|
|
|
446
448
|
: [{ type: "noauth" }],
|
|
447
449
|
},
|
|
448
450
|
}));
|
|
451
|
+
export const HOSTED_TOOLS = hostedTools(TOOLS);
|
|
449
452
|
const ajv = new Ajv({ strict: false, allErrors: true, validateFormats: false });
|
|
450
453
|
const validators = new Map(TOOLS.map((t) => [t.name, ajv.compile(t.inputSchema)]));
|
|
454
|
+
const hostedValidators = new Map(HOSTED_TOOLS.map(t => [t.name, ajv.compile(t.inputSchema)]));
|
|
451
455
|
function str(args, key) {
|
|
452
456
|
const v = args[key];
|
|
453
457
|
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
@@ -467,10 +471,11 @@ export async function callTool(name, args, client, ctx = localContext) {
|
|
|
467
471
|
} };
|
|
468
472
|
}
|
|
469
473
|
async function executeTool(name, args, client, ctx) {
|
|
470
|
-
const
|
|
474
|
+
const availableTools = ctx.mode === "http" ? HOSTED_TOOLS : TOOLS;
|
|
475
|
+
const tool = availableTools.find((t) => t.name === name);
|
|
471
476
|
if (!tool)
|
|
472
477
|
return toolError(`Unknown tool: ${name}`, "unknown_tool");
|
|
473
|
-
const validator = validators.get(name);
|
|
478
|
+
const validator = (ctx.mode === "http" ? hostedValidators : validators).get(name);
|
|
474
479
|
if (!validator(args))
|
|
475
480
|
return toolError(`Invalid arguments: ${ajv.errorsText(validator.errors, { separator: "; " })}`, "invalid_arguments");
|
|
476
481
|
if (name === "create_sandbox_key" && ctx.mode === "http")
|
|
@@ -510,7 +515,8 @@ async function executeTool(name, args, client, ctx) {
|
|
|
510
515
|
"i",
|
|
511
516
|
"want",
|
|
512
517
|
].includes(w)) ?? [];
|
|
513
|
-
const
|
|
518
|
+
const workflows = workflowsForMode(ctx.mode);
|
|
519
|
+
const matches = Object.entries(workflows)
|
|
514
520
|
.map(([key, w]) => ({
|
|
515
521
|
key,
|
|
516
522
|
w,
|
|
@@ -523,11 +529,11 @@ async function executeTool(name, args, client, ctx) {
|
|
|
523
529
|
.sort((a, b) => b.score - a.score);
|
|
524
530
|
const selected = matches.length
|
|
525
531
|
? matches
|
|
526
|
-
: Object.entries(
|
|
532
|
+
: Object.entries(workflows).map(([key, w]) => ({ key, w, score: 0 }));
|
|
527
533
|
const names = new Set(selected.flatMap((m) => [...m.w.tools]));
|
|
528
534
|
return text({
|
|
529
535
|
workflows: selected.map(({ key, w }) => ({ product: key, ...w })),
|
|
530
|
-
tools:
|
|
536
|
+
tools: availableTools.filter((t) => names.has(t.name)).map((t) => ({
|
|
531
537
|
name: t.name,
|
|
532
538
|
description: t.description,
|
|
533
539
|
})),
|
|
@@ -553,7 +559,20 @@ async function executeTool(name, args, client, ctx) {
|
|
|
553
559
|
for (const key of generated.route.query)
|
|
554
560
|
if (args[key] !== undefined)
|
|
555
561
|
query.set(key, String(args[key]));
|
|
556
|
-
|
|
562
|
+
let requestBody = args.body;
|
|
563
|
+
if (ctx.mode === "http" && AGENT_WRITE_TOOLS.has(name) && name !== "create_agent") {
|
|
564
|
+
const bindings = name === "set_agent_tools" ? args.body : args.body?.tools;
|
|
565
|
+
if (Array.isArray(bindings)) {
|
|
566
|
+
// Fetch privately: do not route saved connection settings through model context.
|
|
567
|
+
const existing = await client.getJson(`/v1/agents/${encodeURIComponent(String(args.id))}`);
|
|
568
|
+
const saved = new Map((existing.tools ?? []).map(b => [b.tool_id, b.config]));
|
|
569
|
+
const preserved = bindings.map((b) => ({ ...b, ...(saved.has(b.tool_id) ? { config: saved.get(b.tool_id) } : {}) }));
|
|
570
|
+
requestBody = name === "set_agent_tools" ? preserved : { ...args.body, tools: preserved };
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
const result = await client.json(generated.route.method, path + (query.size ? "?" + query.toString() : ""), requestBody, "idempotency" in generated.route ? { "Idempotency-Key": String(args.idempotency_key) } : undefined);
|
|
574
|
+
return text(ctx.mode === "http" && ["list_agents", "get_agent", ...AGENT_WRITE_TOOLS].includes(name)
|
|
575
|
+
? withoutBindingConfig(result) : result);
|
|
557
576
|
}
|
|
558
577
|
const extra = await extraTool(name, args, client, ctx);
|
|
559
578
|
if (extra)
|
|
@@ -562,7 +581,7 @@ async function executeTool(name, args, client, ctx) {
|
|
|
562
581
|
case "openapi_get":
|
|
563
582
|
return text(await openapiGet(client, args));
|
|
564
583
|
case "get_started":
|
|
565
|
-
return text(
|
|
584
|
+
return text(guideForMode(ctx.mode));
|
|
566
585
|
case "create_sandbox_key": {
|
|
567
586
|
const label = str(args, "label");
|
|
568
587
|
const result = await client.postJson("/v1/sandbox/keys", label ? { label } : {});
|
package/dist/workflows.js
CHANGED
|
@@ -144,3 +144,22 @@ export const SEARCH_TERMS = {
|
|
|
144
144
|
dub: "dubbing translate translation languages audio",
|
|
145
145
|
cast: "narration direct expressive script emotion podcast",
|
|
146
146
|
};
|
|
147
|
+
// Keep every hosted discovery surface consistent with the callable catalog.
|
|
148
|
+
export function workflowsForMode(mode) {
|
|
149
|
+
if (mode === "stdio")
|
|
150
|
+
return WORKFLOWS;
|
|
151
|
+
return { ...WORKFLOWS, calling: { ...WORKFLOWS.calling,
|
|
152
|
+
tools: WORKFLOWS.calling.tools.filter(name => name !== "telephony_buy_number"),
|
|
153
|
+
steps: [WORKFLOWS.calling.steps[0],
|
|
154
|
+
"Use an already-owned number. Number purchasing is unavailable through hosted MCP. Binding changes routing; outbound calls require explicit destination approval, confirm=true and a stable idempotency_key.",
|
|
155
|
+
...WORKFLOWS.calling.steps.slice(2)],
|
|
156
|
+
} };
|
|
157
|
+
}
|
|
158
|
+
export function guideForMode(mode) {
|
|
159
|
+
return mode === "stdio" ? GUIDE : GUIDE + "\nHosted MCP does not purchase numbers or accept connection credentials. Use saved tool IDs; configure connections privately in the PyAI console. Supply only recordings and text you are authorized to process. Do not submit payment-card data, protected health information, government identifiers, or authentication secrets.\n";
|
|
160
|
+
}
|
|
161
|
+
export function instructionsForMode(mode) {
|
|
162
|
+
return mode === "stdio" ? SERVER_INSTRUCTIONS : SERVER_INSTRUCTIONS
|
|
163
|
+
.replace("purchases and real outbound calls need explicit authorization", "real outbound calls need explicit destination authorization; number purchasing is unavailable here")
|
|
164
|
+
.replace(" Current pricing: https://pyai.com/pricing.", " Configure connection credentials privately in the PyAI console; use saved tool IDs here. Do not request restricted personal data or direct users to checkout.");
|
|
165
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyai/mcp",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "PyAI MCP: OAuth-connected voice agents, speech, transcription, compliance, call summaries, dubbing and expressive narration for chat apps and coding agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|