@oneshot-agent/mcp-server 0.28.0 → 0.29.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/README.md CHANGED
@@ -97,7 +97,7 @@ Get CDP credentials at [Coinbase Agentic Wallet](https://docs.cdp.coinbase.com/a
97
97
 
98
98
  ### Read authentication
99
99
 
100
- Read tools (inbox, SMS inbox, notifications, balance, browser profiles) return private, per-agent data. The server wraps the OneShot TypeScript SDK, which signs a short-lived **EIP-712 read proof** (`x-agent-proof`) on each read so the API can verify you control the `X-Agent-ID` wallet. This needs no configuration; it ships in `@oneshot-agent/sdk >= 0.25.0` (the bundled dependency). The server is rolling out read-proof verification in log-only mode, so older callers keep working until enforcement is enabled.
100
+ Read tools (inbox, SMS inbox, notifications, balance, browser profiles) return private, per-agent data. The server wraps the OneShot TypeScript SDK, which signs a short-lived **EIP-712 read proof** (`x-agent-proof`) on each read so the API can verify you control the `X-Agent-ID` wallet. This needs no configuration; it ships in `@oneshot-agent/sdk >= 0.25.0` (the bundled dependency). The API enforces this proof by default — a request with no proof (or a mismatched one) and no valid access token is rejected.
101
101
 
102
102
  ## Remote (hosted)
103
103
 
@@ -226,7 +226,7 @@ instead of the wallet variables for a credits-only session on your own machine.
226
226
  | Tool | Description |
227
227
  |------|-------------|
228
228
  | `oneshot_spend_breakdown` | Spend by tool/category over a period |
229
- | `oneshot_rocs` | Return on Compute Spend analytics |
229
+ | `oneshot_return_on_spend` | Return on spend: cost vs. value produced |
230
230
  | `oneshot_receipts_list` | List spend receipts |
231
231
  | `oneshot_tag_receipt_value` | Tag a receipt with the value it generated |
232
232
 
package/dist/index.js CHANGED
@@ -52,7 +52,7 @@ async function main() {
52
52
  // Create MCP server
53
53
  const server = new Server({
54
54
  name: "oneshot-mcp",
55
- version: "0.28.0", // keep in sync with package.json; guarded by version.test.ts
55
+ version: "0.29.1", // keep in sync with package.json; guarded by version.test.ts
56
56
  }, {
57
57
  capabilities: {
58
58
  tools: {},
@@ -10,3 +10,8 @@ export declare function handleRocs(agent: OneShot, args: Record<string, unknown>
10
10
  export declare function handleReceiptsList(agent: OneShot, args: Record<string, unknown>): Promise<import("@oneshot-agent/sdk").ReceiptsListResult>;
11
11
  export declare function handleRocsByGoal(agent: OneShot, args: Record<string, unknown>): Promise<import("@oneshot-agent/sdk").RoCSByGoalResult>;
12
12
  export declare function handleTagReceiptValue(agent: OneShot, args: Record<string, unknown>): Promise<void>;
13
+ /**
14
+ * Old tool names (renamed in 0.29.1 because "rocs" was unclear to users and
15
+ * to ChatGPT's review scan). Still dispatched, never listed.
16
+ */
17
+ export declare const LEGACY_TOOL_ALIASES: Record<string, (agent: OneShot, args: Record<string, unknown>) => Promise<unknown>>;
@@ -9,8 +9,8 @@ export const spendBreakdownTool = {
9
9
  },
10
10
  };
11
11
  export const rocsTool = {
12
- name: "oneshot_rocs",
13
- description: "Get Return on Compute Spend (RoCS) analytics for the agent over a period. Free.",
12
+ name: "oneshot_return_on_spend",
13
+ description: "Get the agent's return on spend over a period: what its tool calls cost compared with the value they produced (return on compute spend). Free.",
14
14
  inputSchema: {
15
15
  type: "object",
16
16
  properties: {
@@ -54,9 +54,9 @@ export const tagReceiptValueTool = {
54
54
  },
55
55
  };
56
56
  export const rocsByGoalTool = {
57
- name: "oneshot_rocs_by_goal",
58
- description: "Per-cadence RoCS rollup: spend (receipts) vs. value (outcomes) grouped by goal_id. " +
59
- "Answers 'what did this cadence cost vs. earn' in one query. Free.",
57
+ name: "oneshot_return_on_spend_by_goal",
58
+ description: "Return on spend per goal: what each goal cost (receipts) compared with the value it produced (tagged outcomes), grouped by goal_id. " +
59
+ "Answers 'what did this goal cost vs. earn' in one query. Free.",
60
60
  inputSchema: {
61
61
  type: "object",
62
62
  properties: {
@@ -98,3 +98,11 @@ export async function handleTagReceiptValue(agent, args) {
98
98
  label: args.label,
99
99
  });
100
100
  }
101
+ /**
102
+ * Old tool names (renamed in 0.29.1 because "rocs" was unclear to users and
103
+ * to ChatGPT's review scan). Still dispatched, never listed.
104
+ */
105
+ export const LEGACY_TOOL_ALIASES = {
106
+ oneshot_rocs: handleRocs,
107
+ oneshot_rocs_by_goal: handleRocsByGoal,
108
+ };
@@ -0,0 +1,16 @@
1
+ import type { ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
2
+ /**
3
+ * MCP tool annotations for every tool (#999). ChatGPT requires all three hints
4
+ * on every tool, and uses them: a tool that is not read-only asks the user to
5
+ * confirm before it runs.
6
+ *
7
+ * readOnlyHint true = retrieval only (paid lookups included — the only
8
+ * side effect is our own billing)
9
+ * destructiveHint true = deletes, overwrites or revokes something. Sends are
10
+ * additive writes, so false — like any mail app's send.
11
+ * openWorldHint true = reaches the public web or third parties;
12
+ * false = only the caller's own OneShot account data.
13
+ */
14
+ type Hints = Required<Pick<ToolAnnotations, "title" | "readOnlyHint" | "destructiveHint" | "openWorldHint">>;
15
+ export declare const TOOL_ANNOTATIONS: Record<string, Hints>;
16
+ export {};
@@ -0,0 +1,96 @@
1
+ /** Retrieval only. */
2
+ const read = (title, openWorld) => ({ title, readOnlyHint: true, destructiveHint: false, openWorldHint: openWorld });
3
+ /** Changes something. `destructive` only for delete / overwrite / revoke. */
4
+ const write = (title, openWorld, destructive = false) => ({ title, readOnlyHint: false, destructiveHint: destructive, openWorldHint: openWorld });
5
+ const OPEN = true;
6
+ const OWN = false;
7
+ const DESTRUCTIVE = true;
8
+ export const TOOL_ANNOTATIONS = {
9
+ // Communication
10
+ oneshot_email: write("Send email", OPEN),
11
+ oneshot_voice: write("Place a phone call", OPEN),
12
+ oneshot_sms: write("Send a text message", OPEN),
13
+ // Inbox
14
+ oneshot_inbox_list: read("List received emails", OWN),
15
+ oneshot_inbox_get: read("Read a received email", OWN),
16
+ oneshot_sms_inbox_list: read("List received texts", OWN),
17
+ oneshot_sms_inbox_get: read("Read a received text", OWN),
18
+ // Inbound voice
19
+ oneshot_voice_number_provision: write("Get a phone number", OPEN),
20
+ oneshot_voice_numbers: read("List phone numbers", OWN),
21
+ oneshot_voice_inbound_set: write("Set up call answering", OWN, DESTRUCTIVE), // replaces the number's answering settings
22
+ oneshot_voice_inbound_disable: write("Stop answering calls", OWN),
23
+ oneshot_voice_inbound_calls: read("List answered calls", OWN),
24
+ // Research & enrichment
25
+ oneshot_research: read("Deep research", OPEN),
26
+ oneshot_people_search: read("Find people", OPEN),
27
+ oneshot_enrich_profile: read("Look up a person's profile", OPEN),
28
+ oneshot_find_email: read("Find a work email", OPEN),
29
+ oneshot_verify_email: read("Verify an email address", OPEN),
30
+ oneshot_web_search: read("Web search", OPEN),
31
+ oneshot_deep_research_person: read("Research a person", OPEN),
32
+ oneshot_social_profiles: read("Find social profiles", OPEN),
33
+ oneshot_article_search: read("Find articles about a person", OPEN),
34
+ oneshot_person_newsfeed: read("Get a person's recent posts", OPEN),
35
+ oneshot_person_interests: read("Summarize a person's interests", OPEN),
36
+ oneshot_person_interactions: read("Find a person's interactions", OPEN),
37
+ oneshot_company_search: read("Find companies", OPEN),
38
+ oneshot_enrich_company: read("Look up a company", OPEN),
39
+ oneshot_local_search: read("Find local businesses", OPEN),
40
+ oneshot_local_resolve: read("Look up a local business", OPEN),
41
+ oneshot_gov_solicitations: read("Find government contracts", OPEN),
42
+ // Commerce
43
+ oneshot_commerce_search: read("Search products", OPEN),
44
+ oneshot_commerce_buy: write("Buy a product", OPEN),
45
+ // Compute orchestration
46
+ oneshot_compute: write("Start a goal", OPEN),
47
+ oneshot_compute_status: read("Check a goal", OWN),
48
+ oneshot_compute_tasks: read("List a goal's tasks", OWN),
49
+ oneshot_compute_cancel: write("Cancel a goal", OWN, DESTRUCTIVE),
50
+ oneshot_compute_respond: write("Answer a goal's question", OWN),
51
+ oneshot_compute_pause: write("Pause a goal", OWN),
52
+ oneshot_compute_resume: write("Resume a goal", OWN),
53
+ oneshot_compute_fund: write("Add budget to a goal", OWN),
54
+ // Build
55
+ oneshot_build: write("Build a website", OPEN),
56
+ oneshot_update_build: write("Update a website", OPEN, DESTRUCTIVE), // overwrites the live site
57
+ // Browser
58
+ oneshot_browser: write("Browse and act on a website", OPEN),
59
+ oneshot_browser_create_profile: write("Create a browser profile", OWN),
60
+ oneshot_browser_list_profiles: read("List browser profiles", OWN),
61
+ oneshot_browser_delete_profile: write("Delete a browser profile", OWN, DESTRUCTIVE),
62
+ // Web read
63
+ oneshot_web_read: read("Read a web page", OPEN),
64
+ // LinkedIn
65
+ oneshot_linkedin_connect: write("Connect LinkedIn", OPEN),
66
+ oneshot_linkedin_accounts: read("List LinkedIn accounts", OWN),
67
+ oneshot_linkedin_sync: write("Sync LinkedIn messages", OPEN), // paid; imports history into the account
68
+ oneshot_linkedin_conversations: read("List LinkedIn conversations", OWN),
69
+ oneshot_linkedin_messages: read("Read LinkedIn messages", OWN),
70
+ oneshot_linkedin_reply: write("Send a LinkedIn message", OPEN),
71
+ oneshot_linkedin_invite: write("Send a LinkedIn invitation", OPEN),
72
+ oneshot_linkedin_withdraw_invitation: write("Withdraw a LinkedIn invitation", OPEN, DESTRUCTIVE),
73
+ oneshot_linkedin_view_profile: write("View a LinkedIn profile", OPEN), // notify=true is visible to the person
74
+ oneshot_linkedin_react: write("React to a LinkedIn post", OPEN),
75
+ // Domains
76
+ oneshot_list_domains: read("List sending domains", OWN),
77
+ oneshot_pause_domain: write("Pause a sending domain", OWN),
78
+ oneshot_resume_domain: write("Resume a sending domain", OWN),
79
+ // Analytics
80
+ oneshot_spend_breakdown: read("Show spending", OWN),
81
+ oneshot_return_on_spend: read("Show return on spend", OWN),
82
+ oneshot_return_on_spend_by_goal: read("Show return on spend by goal", OWN),
83
+ oneshot_receipts_list: read("List receipts", OWN),
84
+ oneshot_tag_receipt_value: write("Tag a receipt's value", OWN),
85
+ // Account
86
+ oneshot_notifications: read("List notifications", OWN),
87
+ oneshot_mark_notification_read: write("Mark a notification read", OWN),
88
+ oneshot_get_balance: read("Check balance", OWN),
89
+ oneshot_budget_status: read("Check budget", OWN),
90
+ // Approvals
91
+ oneshot_approval_create: write("Ask a person to approve", OPEN),
92
+ oneshot_approval_get: read("Check an approval", OWN),
93
+ oneshot_approval_list: read("List approvals", OWN),
94
+ oneshot_approval_cancel: write("Cancel an approval", OWN, DESTRUCTIVE),
95
+ oneshot_action_policy: read("Show approval rules", OWN),
96
+ };
@@ -22,9 +22,10 @@ import { govSolicitationsTool, handleGovSolicitations } from "./gov.js";
22
22
  import { linkedinConnectTool, linkedinAccountsTool, linkedinSyncTool, linkedinConversationsTool, linkedinMessagesTool, linkedinReplyTool, linkedinViewProfileTool, linkedinReactTool, linkedinInviteTool, linkedinWithdrawInvitationTool, handleLinkedinConnect, handleLinkedinAccounts, handleLinkedinSync, handleLinkedinConversations, handleLinkedinMessages, handleLinkedinReply, handleLinkedinViewProfile, handleLinkedinReact, handleLinkedinInvite, handleLinkedinWithdrawInvitation, } from "./linkedin.js";
23
23
  import { computeTool, computeStatusTool, computeTasksTool, computeCancelTool, computeRespondTool, computePauseTool, computeResumeTool, computeFundTool, handleCompute, handleComputeStatus, handleComputeTasks, handleComputeCancel, handleComputeRespond, handleComputePause, handleComputeResume, handleComputeFund } from "./compute.js";
24
24
  import { listDomainsTool, pauseDomainTool, resumeDomainTool, handleListDomains, handlePauseDomain, handleResumeDomain } from "./domains.js";
25
- import { spendBreakdownTool, rocsTool, rocsByGoalTool, receiptsListTool, tagReceiptValueTool, handleSpendBreakdown, handleRocs, handleRocsByGoal, handleReceiptsList, handleTagReceiptValue } from "./analytics.js";
26
- // All available tools
27
- export const tools = [
25
+ import { TOOL_ANNOTATIONS } from "./annotations.js";
26
+ import { spendBreakdownTool, rocsTool, rocsByGoalTool, receiptsListTool, tagReceiptValueTool, handleSpendBreakdown, handleRocs, handleRocsByGoal, handleReceiptsList, handleTagReceiptValue, LEGACY_TOOL_ALIASES } from "./analytics.js";
27
+ // All available tools, before annotations
28
+ const toolDefinitions = [
28
29
  // Communication
29
30
  emailTool,
30
31
  voiceTool,
@@ -112,6 +113,14 @@ export const tools = [
112
113
  approvalCancelTool,
113
114
  actionPolicyGetTool,
114
115
  ];
116
+ // Every tool carries a human title and the three MCP hints clients rely on
117
+ // (ChatGPT confirms any tool that is not read-only). See annotations.ts.
118
+ export const tools = toolDefinitions.map((tool) => {
119
+ const hints = TOOL_ANNOTATIONS[tool.name];
120
+ if (!hints)
121
+ throw new Error(`Tool ${tool.name} has no annotations — add it to tools/annotations.ts`);
122
+ return { ...tool, title: hints.title, annotations: { ...hints } };
123
+ });
115
124
  // Tool handlers map
116
125
  const handlers = {
117
126
  // Communication
@@ -186,8 +195,10 @@ const handlers = {
186
195
  "oneshot_resume_domain": handleResumeDomain,
187
196
  // Analytics
188
197
  "oneshot_spend_breakdown": handleSpendBreakdown,
189
- "oneshot_rocs": handleRocs,
190
- "oneshot_rocs_by_goal": handleRocsByGoal,
198
+ "oneshot_return_on_spend": handleRocs,
199
+ "oneshot_return_on_spend_by_goal": handleRocsByGoal,
200
+ // Pre-0.29.1 names: callable, never listed, so existing clients keep working.
201
+ ...LEGACY_TOOL_ALIASES,
191
202
  "oneshot_receipts_list": handleReceiptsList,
192
203
  "oneshot_tag_receipt_value": handleTagReceiptValue,
193
204
  // Account
@@ -2,7 +2,7 @@ export const voiceNumberProvisionTool = {
2
2
  name: "oneshot_voice_number_provision",
3
3
  description: "Get this agent a phone number without placing a call, so it can answer calls (then use oneshot_voice_inbound_set). " +
4
4
  "Returns the existing number for free; otherwise buys one and charges the one-time phone registration fee from prepaid credits. " +
5
- "Fails with 402 and buys nothing when credits are too low. Requires a wallet session (not available with an agent access token).",
5
+ "Fails with 402 and buys nothing when credits are too low. Needs a wallet or OAuth session; a plain agent access token cannot buy numbers.",
6
6
  inputSchema: { type: "object", properties: {} },
7
7
  };
8
8
  export const voiceNumbersTool = {
@@ -15,7 +15,7 @@ export const voiceInboundSetTool = {
15
15
  description: "Make one of the agent's numbers answer its own calls. Replaces the whole inbound config. " +
16
16
  "During business hours the assistant follows `prompt`; after hours it takes a message, transfers, or declines. " +
17
17
  "Calls are paid from prepaid credits per started minute and are declined when credits cannot cover the minimum fee. " +
18
- "Requires a wallet session (not available with an agent access token).",
18
+ "Needs a wallet or OAuth session; a plain agent access token can only read these settings.",
19
19
  inputSchema: {
20
20
  type: "object",
21
21
  properties: {
@@ -56,7 +56,7 @@ export const voiceInboundSetTool = {
56
56
  };
57
57
  export const voiceInboundDisableTool = {
58
58
  name: "oneshot_voice_inbound_disable",
59
- description: "Stop answering calls to one of the agent's numbers. The settings are kept, disabled. Free. Requires a wallet session.",
59
+ description: "Stop answering calls to one of the agent's numbers. The settings are kept, disabled. Free. Needs a wallet or OAuth session.",
60
60
  inputSchema: {
61
61
  type: "object",
62
62
  properties: { phone_number_id: { type: "string", description: "Number id from oneshot_voice_numbers" } },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneshot-agent/mcp-server",
3
- "version": "0.28.0",
3
+ "version": "0.29.1",
4
4
  "description": "MCP server for OneShot - 73 tools for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "@coinbase/cdp-sdk": "1.45.0",
27
27
  "@modelcontextprotocol/sdk": "1.27.1",
28
- "@oneshot-agent/sdk": "^0.42.0",
28
+ "@oneshot-agent/sdk": "^0.43.0",
29
29
  "zod": "3.25.76"
30
30
  },
31
31
  "devDependencies": {