@@ -7,8 +7,9 @@ export const MANAGE_FIELD: Tool = {
77 - Field Types: Text, Number, Date, Lookup, Master-Detail, Picklist etc.
88 - Properties: Required, Unique, External ID, Length, Scale etc.
99 - Relationships: Create lookups and master-detail relationships
10+ - Automatically grants Field Level Security to System Administrator (or specified profiles)
1011 Examples: Add Rating__c picklist to Account, Create Account lookup on Custom Object
11- Note: Changes affect metadata and require proper permissions ` ,
12+ Note: Use grantAccessTo parameter to specify profiles, defaults to System Administrator ` ,
1213 inputSchema : {
1314 type : "object" ,
1415 properties : {
@@ -105,6 +106,12 @@ export const MANAGE_FIELD: Tool = {
105106 type : "string" ,
106107 description : "Description of the field" ,
107108 optional : true
109+ } ,
110+ grantAccessTo : {
111+ type : "array" ,
112+ items : { type : "string" } ,
113+ description : "Profile names to grant field access to (defaults to ['System Administrator'])" ,
114+ optional : true
108115 }
109116 } ,
110117 required : [ "operation" , "objectName" , "fieldName" ]
@@ -129,10 +136,104 @@ export interface ManageFieldArgs {
129136 deleteConstraint ?: 'Cascade' | 'Restrict' | 'SetNull' ;
130137 picklistValues ?: Array < { label : string ; isDefault ?: boolean } > ;
131138 description ?: string ;
139+ grantAccessTo ?: string [ ] ;
140+ }
141+
142+ // Helper function to set field permissions (simplified version of the one in manageFieldPermissions.ts)
143+ async function grantFieldPermissions ( conn : any , objectName : string , fieldName : string , profileNames : string [ ] ) : Promise < { success : boolean ; message : string } > {
144+ try {
145+ const fieldApiName = fieldName . endsWith ( '__c' ) || fieldName . includes ( '.' ) ? fieldName : `${ fieldName } __c` ;
146+ const fullFieldName = `${ objectName } .${ fieldApiName } ` ;
147+
148+ // Get profile IDs
149+ const profileQuery = await conn . query ( `
150+ SELECT Id, Name
151+ FROM Profile
152+ WHERE Name IN (${ profileNames . map ( name => `'${ name } '` ) . join ( ', ' ) } )
153+ ` ) ;
154+
155+ if ( profileQuery . records . length === 0 ) {
156+ return { success : false , message : `No profiles found matching: ${ profileNames . join ( ', ' ) } ` } ;
157+ }
158+
159+ const results : any [ ] = [ ] ;
160+ const errors : string [ ] = [ ] ;
161+
162+ for ( const profile of profileQuery . records ) {
163+ try {
164+ // Check if permission already exists
165+ const existingPerm = await conn . query ( `
166+ SELECT Id, PermissionsRead, PermissionsEdit
167+ FROM FieldPermissions
168+ WHERE ParentId IN (
169+ SELECT Id FROM PermissionSet
170+ WHERE IsOwnedByProfile = true
171+ AND ProfileId = '${ profile . Id } '
172+ )
173+ AND Field = '${ fullFieldName } '
174+ AND SobjectType = '${ objectName } '
175+ LIMIT 1
176+ ` ) ;
177+
178+ if ( existingPerm . records . length > 0 ) {
179+ // Update existing permission
180+ await conn . sobject ( 'FieldPermissions' ) . update ( {
181+ Id : existingPerm . records [ 0 ] . Id ,
182+ PermissionsRead : true ,
183+ PermissionsEdit : true
184+ } ) ;
185+ results . push ( profile . Name ) ;
186+ } else {
187+ // Get the PermissionSet ID for this profile
188+ const permSetQuery = await conn . query ( `
189+ SELECT Id FROM PermissionSet
190+ WHERE IsOwnedByProfile = true
191+ AND ProfileId = '${ profile . Id } '
192+ LIMIT 1
193+ ` ) ;
194+
195+ if ( permSetQuery . records . length > 0 ) {
196+ // Create new permission
197+ await conn . sobject ( 'FieldPermissions' ) . create ( {
198+ ParentId : permSetQuery . records [ 0 ] . Id ,
199+ SobjectType : objectName ,
200+ Field : fullFieldName ,
201+ PermissionsRead : true ,
202+ PermissionsEdit : true
203+ } ) ;
204+ results . push ( profile . Name ) ;
205+ } else {
206+ errors . push ( profile . Name ) ;
207+ }
208+ }
209+ } catch ( error ) {
210+ errors . push ( profile . Name ) ;
211+ console . error ( `Error granting permission to ${ profile . Name } :` , error ) ;
212+ }
213+ }
214+
215+ if ( results . length > 0 ) {
216+ return {
217+ success : true ,
218+ message : `Field Level Security granted to: ${ results . join ( ', ' ) } ${ errors . length > 0 ? `. Failed for: ${ errors . join ( ', ' ) } ` : '' } `
219+ } ;
220+ } else {
221+ return {
222+ success : false ,
223+ message : `Could not grant Field Level Security to any profiles.`
224+ } ;
225+ }
226+ } catch ( error ) {
227+ console . error ( 'Error granting field permissions:' , error ) ;
228+ return {
229+ success : false ,
230+ message : `Field Level Security configuration failed.`
231+ } ;
232+ }
132233}
133234
134235export async function handleManageField ( conn : any , args : ManageFieldArgs ) {
135- const { operation, objectName, fieldName, type, ...fieldProps } = args ;
236+ const { operation, objectName, fieldName, type, grantAccessTo , ...fieldProps } = args ;
136237
137238 try {
138239 if ( operation === 'create' ) {
@@ -205,10 +306,21 @@ export async function handleManageField(conn: any, args: ManageFieldArgs) {
205306 const result = await conn . metadata . create ( 'CustomField' , metadata ) ;
206307
207308 if ( result && ( Array . isArray ( result ) ? result [ 0 ] . success : result . success ) ) {
309+ let permissionMessage = '' ;
310+
311+ // Grant Field Level Security (default to System Administrator if not specified)
312+ const profilesToGrant = grantAccessTo && grantAccessTo . length > 0 ? grantAccessTo : [ 'System Administrator' ] ;
313+
314+ // Wait a moment for field to be fully created
315+ await new Promise ( resolve => setTimeout ( resolve , 2000 ) ) ;
316+
317+ const permissionResult = await grantFieldPermissions ( conn , objectName , fieldName , profilesToGrant ) ;
318+ permissionMessage = `\n${ permissionResult . message } ` ;
319+
208320 return {
209321 content : [ {
210322 type : "text" ,
211- text : `Successfully created custom field ${ fieldName } __c on ${ objectName } `
323+ text : `Successfully created custom field ${ fieldName } __c on ${ objectName } . ${ permissionMessage } `
212324 } ] ,
213325 isError : false ,
214326 } ;
0 commit comments