Skip to content

Commit de18a8a

Browse files
feat: implement refund APIs as tools for mcp server (#11)
* feat: implement refund update API endpoint Add update_refund tool to update refund notes according to Razorpay API documentation. This implements the PATCH /v1/refunds/:id/ endpoint functionality and includes appropriate test coverage for the new tool. * style: keep line length under 80 characters in refunds.go * ref: improve refunds tool parameter validation and descriptions * chore: update README.md
1 parent ff55978 commit de18a8a

File tree

4 files changed

+538
-0
lines changed

4 files changed

+538
-0
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ Currently, the Razorpay MCP Server provides the following tools:
1414
| `create_order` | Creates an order | [Order](https://razorpay.com/docs/api/orders/create/)
1515
| `fetch_order` | Fetch order with ID | [Order](https://razorpay.com/docs/api/orders/fetch-with-id)
1616
| `fetch_all_orders` | Fetch all orders | [Order](https://razorpay.com/docs/api/orders/fetch-all)
17+
| `create_refund` | Creates a refund | [Refund](https://razorpay.com/docs/api/refunds/create-instant/)
18+
| `fetch_refund` | Fetch refund details with ID | [Refund](https://razorpay.com/docs/api/refunds/fetch-with-id/)
19+
| `update_refund` | Update refund notes with ID | [Refund](https://razorpay.com/docs/api/refunds/update/)
1720

1821
## Use Cases
1922
- Workflow Automation: Automate your day to day workflow using Razorpay MCP Server.

pkg/razorpay/refunds.go

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package razorpay
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log/slog"
7+
8+
rzpsdk "github.com/razorpay/razorpay-go"
9+
10+
"github.com/razorpay/razorpay-mcp-server/pkg/mcpgo"
11+
)
12+
13+
// CreateRefund returns a tool that creates a normal refund for a payment
14+
func CreateRefund(
15+
_ *slog.Logger,
16+
client *rzpsdk.Client,
17+
) mcpgo.Tool {
18+
parameters := []mcpgo.ToolParameter{
19+
mcpgo.WithString(
20+
"payment_id",
21+
mcpgo.Description("Unique identifier of the payment which "+
22+
"needs to be refunded. ID should have a pay_ prefix."),
23+
mcpgo.Required(),
24+
),
25+
mcpgo.WithNumber(
26+
"amount",
27+
mcpgo.Description("Payment amount in the smallest currency unit "+
28+
"(e.g., for ₹295, use 29500)"),
29+
),
30+
mcpgo.WithString(
31+
"speed",
32+
mcpgo.Description("The speed at which the refund is to be "+
33+
"processed. Default is 'normal'. For instant refunds, speed "+
34+
"is set as 'optimum'."),
35+
),
36+
mcpgo.WithObject(
37+
"notes",
38+
mcpgo.Description("Key-value pairs used to store additional "+
39+
"information. A maximum of 15 key-value pairs can be included."),
40+
),
41+
mcpgo.WithString(
42+
"receipt",
43+
mcpgo.Description("A unique identifier provided by you for "+
44+
"your internal reference."),
45+
),
46+
}
47+
48+
handler := func(
49+
ctx context.Context,
50+
r mcpgo.CallToolRequest,
51+
) (*mcpgo.ToolResult, error) {
52+
paymentID, err := RequiredParam[string](r, "payment_id")
53+
if result, err := HandleValidationError(err); result != nil {
54+
return result, err
55+
}
56+
57+
data := make(map[string]interface{})
58+
59+
var amount int
60+
amount, err = OptionalInt(r, "amount")
61+
if result, err := HandleValidationError(err); result != nil {
62+
return result, err
63+
}
64+
65+
speed, err := OptionalParam[string](r, "speed")
66+
if result, err := HandleValidationError(err); result != nil {
67+
return result, err
68+
}
69+
if speed != "" {
70+
data["speed"] = speed
71+
}
72+
73+
notes, err := OptionalParam[map[string]interface{}](r, "notes")
74+
if result, err := HandleValidationError(err); result != nil {
75+
return result, err
76+
}
77+
if notes != nil {
78+
data["notes"] = notes
79+
}
80+
81+
receipt, err := OptionalParam[string](r, "receipt")
82+
if result, err := HandleValidationError(err); result != nil {
83+
return result, err
84+
}
85+
if receipt != "" {
86+
data["receipt"] = receipt
87+
}
88+
89+
refund, err := client.Payment.Refund(paymentID, amount, data, nil)
90+
if err != nil {
91+
return mcpgo.NewToolResultError(
92+
fmt.Sprintf("creating refund failed: %s", err.Error())), nil
93+
}
94+
95+
return mcpgo.NewToolResultJSON(refund)
96+
}
97+
98+
return mcpgo.NewTool(
99+
"create_refund",
100+
"Use this tool to create a normal refund for a payment. "+
101+
"Amount should be in the smallest currency unit (e.g., for ₹295, use 29500)",
102+
parameters,
103+
handler,
104+
)
105+
}
106+
107+
// FetchRefund returns a tool that fetches a refund by ID
108+
func FetchRefund(
109+
_ *slog.Logger,
110+
client *rzpsdk.Client,
111+
) mcpgo.Tool {
112+
parameters := []mcpgo.ToolParameter{
113+
mcpgo.WithString(
114+
"refund_id",
115+
mcpgo.Description(
116+
"Unique identifier of the refund which is to be retrieved. "+
117+
"ID should have a rfnd_ prefix."),
118+
mcpgo.Required(),
119+
),
120+
}
121+
122+
handler := func(
123+
ctx context.Context,
124+
r mcpgo.CallToolRequest,
125+
) (*mcpgo.ToolResult, error) {
126+
refundID, err := RequiredParam[string](r, "refund_id")
127+
if result, err := HandleValidationError(err); result != nil {
128+
return result, err
129+
}
130+
131+
refund, err := client.Refund.Fetch(refundID, nil, nil)
132+
if err != nil {
133+
return mcpgo.NewToolResultError(
134+
fmt.Sprintf("fetching refund failed: %s", err.Error())), nil
135+
}
136+
137+
return mcpgo.NewToolResultJSON(refund)
138+
}
139+
140+
return mcpgo.NewTool(
141+
"fetch_refund",
142+
"Use this tool to retrieve the details of a specific refund using its id.",
143+
parameters,
144+
handler,
145+
)
146+
}
147+
148+
// UpdateRefund returns a tool that updates a refund's notes
149+
func UpdateRefund(
150+
_ *slog.Logger,
151+
client *rzpsdk.Client,
152+
) mcpgo.Tool {
153+
parameters := []mcpgo.ToolParameter{
154+
mcpgo.WithString(
155+
"refund_id",
156+
mcpgo.Description("Unique identifier of the refund which "+
157+
"needs to be updated. ID should have a rfnd_ prefix."),
158+
mcpgo.Required(),
159+
),
160+
mcpgo.WithObject(
161+
"notes",
162+
mcpgo.Description("Key-value pairs used to store additional "+
163+
"information. A maximum of 15 key-value pairs can be included, "+
164+
"with each value not exceeding 256 characters."),
165+
mcpgo.Required(),
166+
),
167+
}
168+
169+
handler := func(
170+
ctx context.Context,
171+
r mcpgo.CallToolRequest,
172+
) (*mcpgo.ToolResult, error) {
173+
refundID, err := RequiredParam[string](r, "refund_id")
174+
if result, err := HandleValidationError(err); result != nil {
175+
return result, err
176+
}
177+
178+
notesType := RequiredParam[map[string]interface{}]
179+
notes, err := notesType(r, "notes")
180+
if result, err := HandleValidationError(err); result != nil {
181+
return result, err
182+
}
183+
184+
data := make(map[string]interface{})
185+
data["notes"] = notes
186+
187+
refund, err := client.Refund.Update(refundID, data, nil)
188+
if err != nil {
189+
return mcpgo.NewToolResultError(
190+
fmt.Sprintf("updating refund failed: %s", err.Error())), nil
191+
}
192+
193+
return mcpgo.NewToolResultJSON(refund)
194+
}
195+
196+
return mcpgo.NewTool(
197+
"update_refund",
198+
"Use this tool to update the notes for a specific refund. "+
199+
"Only the notes field can be modified.",
200+
parameters,
201+
handler,
202+
)
203+
}

0 commit comments

Comments
 (0)